views:

2147

answers:

3

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 XLST 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).

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

Here is a sample of the xml:

<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom'&gt;
  <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'/&gt;
  <author>
    <name>some author</name>
    <uri>http://someuri.co.uk&lt;/uri&gt;
  </author>
  <generator uri='http://aardvarkmedia.co.uk/'&gt;AardvarkMedia script</generator>
    <entry>
        <id>http://soemaddress.co.uk/branded3/80406&lt;/id&gt;
        <title type='html'>My Ttile</title>
        <link rel='alternate' href='http://www.someurl.co.uk'/&gt;
        <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'&gt;
                <div class='vcard'>
                    <p class='fn org'>some title</p>
                    <p class='adr'>
                        <abbr class='type' title='POSTAL'></abbr>
                        <span class='street-address'>54 Some Street</span>,
                        <span class='locality'></span>,
                        <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#'&gt;
            <lat>51.123456789</lat><long>-0.11111111</long>
        </Point>
    </entry>
</feed>

This is 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

Thanks in advance

+3  A: 

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

*[local-name()='category']/@*[local-name()='term']
Santiago Palladino
works perfect thanks a lot
tigermain
This was very useful although I wish MS would integrate default namespace handling as an option.....
Adrian
A: 

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:

<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.

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.

elarson
+2  A: 

According to 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".

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.

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.

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'"):

      <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.

Dominic Cronin