Firoz Ansari
Firoz Ansari

Reputation: 2515

XSLT unable to find XPATH for for-each

I am trying to debug an issue related to xpath. I created a variable $MetaData in my XSLT assigning a xml document but for some reason, foreach loop didn't able to locate its child and I couldn't able to get inside foreach loop.

XSLT:

<!-- language: lang-xslt -->
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns="http://www.w3.org/TR/xhtml1/strict"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt">

  <xsl:variable name="_MetaData">
    <MetaData>
      <EmployeeId>1233</EmployeeId>
      <EmployeeName>abcd</EmployeeName>
    </MetaData>
  </xsl:variable>
  <xsl:variable name="MetaData" select="msxsl:node-set($_MetaData)"></xsl:variable>

  <xsl:template match="*|@*">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[local-name()='MetaDataTag']">
    <xsl:copy>

      <MetaData VocabularyOwner="acme.com" Vocabulary="MetaData">
        <xsl:for-each select="$MetaData//MetaData/*">
          <xsl:element name="Occurrence">
            <xsl:attribute name="Id">
              <xsl:value-of select="local-name(.)"/>
            </xsl:attribute>
            <xsl:attribute name="Value">
              <xsl:value-of select="string(.)"/>
            </xsl:attribute>
          </xsl:element>
        </xsl:for-each>
      </MetaData>

    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

XML:

<?xml version="1.0" encoding="utf-8" ?>
<Envelope>
  <MetaDataTag />
</Envelope>

If I remove xmlns xmlns="http://www.w3.org/TR/xhtml1/strict" namespace, everything seems working fine and I am able to get inside the loop. I am not sure how can I resolve this issue without removing xmlns="http://www.w3.org/TR/xhtml1/strict" namespace.

Upvotes: 0

Views: 664

Answers (1)

ThW
ThW

Reputation: 19482

If you define the default namespace in the XSLT the nodes in your variable will be in that namespace. Xpath does not have a default namespace so $MetaData//MetaData/* will not match the {http://www.w3.org/TR/xhtml1/strict}MetaData element node.

One solution is to ignore the namespaces using local-name().

`$MetaData//*[local-name() = 'MetaData']/*`

Or you can define an (additional) prefix for your Xpath expressions...

<xsl:stylesheet
  version="1.0"
  xmlns="http://www.w3.org/TR/xhtml1/strict"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xhtml="http://www.w3.org/TR/xhtml1/strict">

  ...
</xsl:stylesheet>

... and use it in the expression.

`$MetaData//xhtml:MetaData/*`

But the tags are not valid in the XHTML namespace so it would be a better idea create the data elements in the empty namespace:

<xsl:variable name="_MetaData">
  <MetaData xmlns="">
    <EmployeeId>1233</EmployeeId>
    <EmployeeName>abcd</EmployeeName>
  </MetaData>
</xsl:variable>
<xsl:variable name="MetaData" select="msxsl:node-set($_MetaData)"/>

Or you define a specific namespace for them...

<xsl:stylesheet
  version="1.0"
  xmlns="http://www.w3.org/TR/xhtml1/strict"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:data="urn:data">

  <xsl:variable name="_MetaData">
    <data:MetaData>
      <data:EmployeeId>1233</data:EmployeeId>
      <data:EmployeeName>abcd</data:EmployeeName>
    </data:MetaData>
  </xsl:variable>
  <xsl:variable name="MetaData" select="msxsl:node-set($_MetaData)"/>
  ...
</xsl:stylesheet>

to use in the expression:

$MetaData//data:MetaData/*

Upvotes: 1

Related Questions