views:

41

answers:

2

I need to navigate through this xml tree.

<publication>
    <corporate>
        <contentItem>
            <metadata>meta</metadata>
            <content>html</content>
        </contentItem>
        <contentItem >
            <metadata>meta1</metadata>
            <content>html1</content>
        </contentItem>
    </corporate>
    <eurasia-and-africa>
       ... 
    </eurasia-and-africa>
    <europe>
       ...
    </europe>
</publication>

and convert it to html with this stylesheet

 <ul>
     <xsl:variable name="itemsNode" select="concat('publicationManifest/',$group,'/contentItem')"></xsl:variable>
     <xsl:for-each select="$itemsNode">
         <li>
        <xsl:value-of select="content"/>
         </li>
    </xsl:for-each>
</ul>

$group is a parameter with name of group for example "corporate". I have an error with compilation of this stylsheet. SystemID: D:\1\contentsTransform.xslt

Engine name: Saxon6.5.5
Severity: error
Description: The value is not a node-set
Start location: 18:0

What the matter?

+2  A: 

You cannot build and evaluate dynamic XPath expressions. And 99.9% of the time, you do not need to. Corollary: if you feel the need to dynamically evaluate XPath, you are very likely doing something wrong.

Declare your $pGroup parameter:

<xsl:param name="pGroup" select="''" />

…make a template for your document element (<publication>):

<xsl:template match="publication">
  <body>
    <!-- select only elements with the right name here -->
    <xsl:apply-templates select="*[name() = $pGroup]" />
  </body>
</xsl:template>

…and one for arbitrary elements that contain <contentItem> elements:

<xsl:template match="*[contentItem]">
  <ul>
    <xsl:apply-templates select="contentItem" />
  </ul>
</xsl:template>

…and one for <contentItem> elements themselves:

<xsl:template match="contentItem">
  <li>
    <xsl:value-of select="content" />
  </ul>
</xsl:template>

Done.

Tomalak
I need to display only content of one node - for example <corporate> and need to manage it by parameter.
Artic
@Artic: See changed answer.
Tomalak
+2  A: 

In XSLT this can be easily achieved in the following way:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="pGroup" select="'corporate'"/>

 <xsl:template match="/">
   <ol>
       <xsl:for-each select="/*/*[name()=$pGroup]/contentItem">
        <li>
            <xsl:value-of select="content"/>
        </li>
       </xsl:for-each>
   </ol>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document, the wanted result is produced:

<ol>
    <li>html</li>
    <li>html1</li>
</ol>

Do note the use of the XPath name() function.

Dimitre Novatchev
Thanks a lot. Works fine.
Artic