在使用具有未知命名空间的XSLT时,如何获取属性值?

时间:2022-01-12 19:37:47

I am receiving a 3rd party feed of which I cannot be certain of the namespace so I am currently having to use the local-name() function in my XSLT to get the element values. However I need to get an attribute from one such element and I don't know how to do this when the namespaces are unknown (hence need for local-name() function).

我收到第三方提要,我不能确定命名空间,所以我当前不得不在我的XSLT中使用local-name()函数来获取元素值。但是我需要从一个这样的元素中获取一个属性,当命名空间未知时我不知道如何执行此操作(因此需要local-name()函数)。

N.B. I am using .net 2.0 to process the XSLT

注:我使用.net 2.0来处理XSLT

Here is a sample of the XML:

以下是XML的示例:

<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
   <id>some id</id>
   <title>some title</title>
   <updated>2008-09-11T15:53:31+01:00</updated>
   <link rel="self" href="http://www.somefeedurl.co.uk" />
   <author>
      <name>some author</name>
      <uri>http://someuri.co.uk</uri>
   </author>
   <generator uri="http://aardvarkmedia.co.uk/">AardvarkMedia script</generator>
   <entry>
      <id>http://soemaddress.co.uk/branded3/80406</id>
      <title type="html">My Ttile</title>
      <link rel="alternate" href="http://www.someurl.co.uk" />
      <updated>2008-02-13T00:00:00+01:00</updated>
      <published>2002-09-11T14:16:20+01:00</published>
      <category term="mycategorytext" label="restaurant">Test</category>
      <content type="xhtml">
         <div xmlns="http://www.w3.org/1999/xhtml">
            <div class="vcard">
               <p class="fn org">some title</p>
               <p class="adr">
                  <abbr class="type" title="POSTAL" />
                  <span class="street-address">54 Some Street</span>
                  ,
                  <span class="locality" />
                  ,
                  <span class="country-name">UK</span>
               </p>
               <p class="tel">
                  <span class="value">0123456789</span>
               </p>
               <div class="geo">
                  <span class="latitude">51.99999</span>
                  ,
                  <span class="longitude">-0.123456</span>
               </div>
               <p class="note">
                  <span class="type">Review</span>
                  <span class="value">Some content</span>
               </p>
               <p class="note">
                  <span class="type">Overall rating</span>
                  <span class="value">8</span>
               </p>
            </div>
         </div>
      </content>
      <category term="cuisine-54" label="Spanish" />
      <Point xmlns="http://www.w3.org/2003/01/geo/wgs84_pos#">
         <lat>51.123456789</lat>
         <long>-0.11111111</long>
      </Point>
   </entry>
</feed>

This is XSLT

这是XSLT

<?xml version="1.0" encoding="UTF-8" ?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:wgs="http://www.w3.org/2003/01/geo/wgs84_pos#" exclude-result-prefixes="atom wgs">
  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="uniqueVenuesKey" match="entry" use="id"/>
  <xsl:key name="uniqueCategoriesKey" match="entry" use="category/@term"/>

  <xsl:template match="/">
    <locations>
      <!-- Get all unique venues -->
      <xsl:for-each select="/*[local-name()='feed']/*[local-name()='entry']">
        <xsl:variable name="CurrentVenueKey" select="*[local-name()='id']" ></xsl:variable>
        <xsl:variable name="CurrentVenueName" select="*[local-name()='title']" ></xsl:variable>
        <xsl:variable name="CurrentVenueAddress1" select="*[local-name()='content']/*[local-name()='div']/*[local-name()='div']/*[local-name()='p'][@class='adr']/*[local-name()='span'][@class='street-address']" ></xsl:variable>
        <xsl:variable name="CurrentVenueCity" select="*[local-name()='content']/*[local-name()='div']/*[local-name()='div']/*[local-name()='p'][@class='adr']/*[local-name()='span'][@class='locality']" ></xsl:variable>
        <xsl:variable name="CurrentVenuePostcode" select="*[local-name()='postcode']" ></xsl:variable>
        <xsl:variable name="CurrentVenueTelephone" select="*[local-name()='telephone']" ></xsl:variable>
        <xsl:variable name="CurrentVenueLat" select="*[local-name()='Point']/*[local-name()='lat']" ></xsl:variable>
        <xsl:variable name="CurrentVenueLong" select="*[local-name()='Point']/*[local-name()='long']" ></xsl:variable>
        <xsl:variable name="CurrentCategory" select="WHATDOIPUTHERE"></xsl:variable>

            <location>
              <locationName>
                <xsl:value-of select = "$CurrentVenueName" />
              </locationName>
              <category>
                <xsl:value-of select = "$CurrentCategory" />
              </category>
              <description>
                  <xsl:value-of select = "$CurrentVenueName" />
              </description>
              <venueAddress>
                <streetName>
                  <xsl:value-of select = "$CurrentVenueAddress1" />
                </streetName>
                <town>
                  <xsl:value-of select = "$CurrentVenueCity" />
                </town>
                <postcode>
                  <xsl:value-of select = "$CurrentVenuePostcode" />
                </postcode>
                <wgs84_latitude>
                  <xsl:value-of select = "$CurrentVenueLat" />
                </wgs84_latitude>
                <wgs84_longitude>
                  <xsl:value-of select = "$CurrentVenueLong" />
                </wgs84_longitude>
              </venueAddress>
              <venuePhone>
                <phonenumber>
                  <xsl:value-of select = "$CurrentVenueTelephone" />
                </phonenumber>
              </venuePhone>
          </location>
        </xsl:for-each>
    </locations>
  </xsl:template>
</xsl:stylesheet>

I'm trying to replace the $CurrentCategory variable the appropriate code to display mycategorytext

我正在尝试将$ CurrentCategory变量替换为适当的代码以显示mycategorytext

3 个解决方案

#1


12  

I don't have an XSLT editor here, but have you tried using

我这里没有XSLT编辑器,但您尝试过使用

*[local-name()='category']/@*[local-name()='term']

#2


2  

According to http://www.w3.org/TR/2006/REC-xml-names-20060816/#scoping-defaulting

根据http://www.w3.org/TR/2006/REC-xml-names-20060816/#scoping-defaulting

"Default namespace declarations do not apply directly to attribute names; the interpretation of unprefixed attributes is determined by the element on which they appear."

“默认名称空间声明不直接应用于属性名称;未加前缀属性的解释由它们出现的元素决定。”

This means that your attributes aren't in a namespace. Just use "@term".

这意味着您的属性不在命名空间中。只需使用“@term”即可。

Just to be a bit clearer, there is no need for using local-name() to solve this problem. The conventional way to deal with it would be to declare a prefix for the atom namespace in your XSLT, and then use that in your xpath queries.

为了更清楚一点,不需要使用local-name()来解决这个问题。处理它的传统方法是在XSLT中为atom命名空间声明一个前缀,然后在xpath查询中使用它。

You have already got this declaration on your stylesheet element (xmlns:atom="http://www.w3.org/2005/Atom"), so all that remains is to use it.

你已经在样式表元素上得到了这个声明(xmlns:atom =“http://www.w3.org/2005/Atom”),所以剩下的就是使用它。

As I have already explained, the attribute is not affected by the default namespace, so your code would look like this (assuming that you were to add "xmlns:xhtml='http://www.w3.org/1999/xhtml'"):

正如我已经解释的那样,该属性不受默认命名空间的影响,因此您的代码将如下所示(假设您要添加“xmlns:xhtml ='http://www.w3.org/1999/xhtml' “):

      <xsl:for-each select="/atom:feed/atom:entry">
        <xsl:variable name="CurrentVenueKey" select="atom:id" />
        <xsl:variable name="CurrentVenueName" select="atom:title" />
        <xsl:variable name="CurrentVenueAddress1" 
             select="atom:content/xhtml:div/xhtml:div/xhtml:p[@class='adr']/xhtml:span[@class='street-address']" />
        <xsl:variable name="CurrentVenueCity" 
             select="atom:content/xhtml:div/xhtml:div'/xhtml:p[@class='adr']/xhtml:span[@class='locality'] />
...
        <xsl:variable name="CurrentCategory" select="atom:category/@term" />

..... 

local-name() can be very useful if you really don't know the structure of the XML you are transforming, but in this case, if you receive anything other than what you're expecting, it will break in any case.

如果你真的不知道你正在转换的XML的结构,local-name()会非常有用,但在这种情况下,如果你收到的东西不是你所期望的,那么无论如何它都会破坏。

#3


0  

I'm not really sure why you have to use local-name(), but if you share a little more info as to what xslt processor you are using along with the language, I'll be that can be figured out. I say this b/c you should be able to do something like:

我不确定为什么你必须使用local-name(),但是如果你分享一些关于你使用的xslt处理器以及语言的更多信息,那么我就可以理解了。我说这个b / c你应该可以这样做:

<xsl:stylesheet xmlns="http://www.w3.org/2005/Atom" ..>

<xsl:template match="feed">
  <xsl:apply-templates />
</xsl:template>

<xsl:template match="entry">
  ... 
  <xsl:variable name="current-category" select="category/@term" />
  ...
</xsl:template>

The two things I'm hoping help you out are the xmlns declaration at the top without a prefix. That sets the default namespace so you don't have to use the namespace prefixes. Likewise, you could call do 'xmlns:a="http://www.w3.org/2005/Atom"' and then do 'select="a:feed"'. The other thing to notice is using the '@term' which selects attributes. If you wanted to match on any attribute '@*' works just like it would for elements.

我希望帮助你的两件事是顶部的xmlns声明没有前缀。这将设置默认命名空间,因此您不必使用命名空间前缀。同样,您可以调用do'xmlns:a =“http://www.w3.org/2005/Atom”'然后执行'select =“a:feed”'。另一件需要注意的事情是使用选择属性的'@term'。如果你想匹配任何属性'@ *'就像它对元素一样。

Again, depending on the processor, there might be other helpful tools at your disposal so if you can provide a little more information it might help. Also, the XSL mailing list might another helpful resource.

同样,根据处理器的不同,可能还有其他有用的工具供您使用,因此如果您可以提供更多信息,则可能有所帮助。此外,XSL邮件列表可能是另一个有用的资源。

#1


12  

I don't have an XSLT editor here, but have you tried using

我这里没有XSLT编辑器,但您尝试过使用

*[local-name()='category']/@*[local-name()='term']

#2


2  

According to http://www.w3.org/TR/2006/REC-xml-names-20060816/#scoping-defaulting

根据http://www.w3.org/TR/2006/REC-xml-names-20060816/#scoping-defaulting

"Default namespace declarations do not apply directly to attribute names; the interpretation of unprefixed attributes is determined by the element on which they appear."

“默认名称空间声明不直接应用于属性名称;未加前缀属性的解释由它们出现的元素决定。”

This means that your attributes aren't in a namespace. Just use "@term".

这意味着您的属性不在命名空间中。只需使用“@term”即可。

Just to be a bit clearer, there is no need for using local-name() to solve this problem. The conventional way to deal with it would be to declare a prefix for the atom namespace in your XSLT, and then use that in your xpath queries.

为了更清楚一点,不需要使用local-name()来解决这个问题。处理它的传统方法是在XSLT中为atom命名空间声明一个前缀,然后在xpath查询中使用它。

You have already got this declaration on your stylesheet element (xmlns:atom="http://www.w3.org/2005/Atom"), so all that remains is to use it.

你已经在样式表元素上得到了这个声明(xmlns:atom =“http://www.w3.org/2005/Atom”),所以剩下的就是使用它。

As I have already explained, the attribute is not affected by the default namespace, so your code would look like this (assuming that you were to add "xmlns:xhtml='http://www.w3.org/1999/xhtml'"):

正如我已经解释的那样,该属性不受默认命名空间的影响,因此您的代码将如下所示(假设您要添加“xmlns:xhtml ='http://www.w3.org/1999/xhtml' “):

      <xsl:for-each select="/atom:feed/atom:entry">
        <xsl:variable name="CurrentVenueKey" select="atom:id" />
        <xsl:variable name="CurrentVenueName" select="atom:title" />
        <xsl:variable name="CurrentVenueAddress1" 
             select="atom:content/xhtml:div/xhtml:div/xhtml:p[@class='adr']/xhtml:span[@class='street-address']" />
        <xsl:variable name="CurrentVenueCity" 
             select="atom:content/xhtml:div/xhtml:div'/xhtml:p[@class='adr']/xhtml:span[@class='locality'] />
...
        <xsl:variable name="CurrentCategory" select="atom:category/@term" />

..... 

local-name() can be very useful if you really don't know the structure of the XML you are transforming, but in this case, if you receive anything other than what you're expecting, it will break in any case.

如果你真的不知道你正在转换的XML的结构,local-name()会非常有用,但在这种情况下,如果你收到的东西不是你所期望的,那么无论如何它都会破坏。

#3


0  

I'm not really sure why you have to use local-name(), but if you share a little more info as to what xslt processor you are using along with the language, I'll be that can be figured out. I say this b/c you should be able to do something like:

我不确定为什么你必须使用local-name(),但是如果你分享一些关于你使用的xslt处理器以及语言的更多信息,那么我就可以理解了。我说这个b / c你应该可以这样做:

<xsl:stylesheet xmlns="http://www.w3.org/2005/Atom" ..>

<xsl:template match="feed">
  <xsl:apply-templates />
</xsl:template>

<xsl:template match="entry">
  ... 
  <xsl:variable name="current-category" select="category/@term" />
  ...
</xsl:template>

The two things I'm hoping help you out are the xmlns declaration at the top without a prefix. That sets the default namespace so you don't have to use the namespace prefixes. Likewise, you could call do 'xmlns:a="http://www.w3.org/2005/Atom"' and then do 'select="a:feed"'. The other thing to notice is using the '@term' which selects attributes. If you wanted to match on any attribute '@*' works just like it would for elements.

我希望帮助你的两件事是顶部的xmlns声明没有前缀。这将设置默认命名空间,因此您不必使用命名空间前缀。同样,您可以调用do'xmlns:a =“http://www.w3.org/2005/Atom”'然后执行'select =“a:feed”'。另一件需要注意的事情是使用选择属性的'@term'。如果你想匹配任何属性'@ *'就像它对元素一样。

Again, depending on the processor, there might be other helpful tools at your disposal so if you can provide a little more information it might help. Also, the XSL mailing list might another helpful resource.

同样,根据处理器的不同,可能还有其他有用的工具供您使用,因此如果您可以提供更多信息,则可能有所帮助。此外,XSL邮件列表可能是另一个有用的资源。