1

I'm just starting out with XSLT, so bear with me. I am processing a fairly complex document with a structure similar to the one below. It is divided into two sections, data and meta. For each data/item I need to look up the "actual" class in the corresponding meta/item.

<root>
  <data>
    <item id="i1">
      <h3 id="p2">akkakk</h3>
      <p id="p3">osijaoid</p>
      <p id="p4">jqidqjwd</p>
    <item>
  </data>
  <meta>
    <item ref="i1">
      <p ref="p2" class="heading"/>
      <p ref="p3" class="heading"/>
      <p ref="p4" class="body"/>
    </item>
  </meta>
</root>

I need to group adjacent p elements in meta on their class attribute. I thought a helper function could make this a bit cleaner:

<xsl:function name="fn:node-groups" as="node()*">
  <xsl:param name="parent"/>
  <xsl:variable name="nodeRefs" select="root($parent)//meta/item[@ref = $parent/@id]/p"/>
  <xsl:for-each-group select="$nodeRefs" group-adjacent="@class">
    <group class="{@class}">
      <xsl:for-each select="current-group()">
        <node ref="{@ref}"/>
      </xsl:for-each>
    </group>
  </xsl:for-each-group>
</xsl:function>

And then use it when processing the data nodes, like so. My problem is that I can not select further from the nodeset returned by the function.

<xsl:template match="//data/item">
  <!-- works -->
  <xsl:variable name="test1" select="fn:node-groups(.)"/>
  <!-- works -->
  <xsl:variable name="test2" select="fn:node-groups(.)/*"/>
  <!-- does not work -->
  <xsl:variable name="test3" select="fn:node-groups(.)/group[@class = 'heading']"/>
</xsl:template>

I can write a star as in test2, and that gives me all node nodes. But anything else just gives me an empty nodeset. Or at least it looks that way, but at this point I really don't know anymore.

1 Answer 1

1

I suppose your stylesheet has an xmlns="http://example.com/foo" namespace declaration scope for the function that puts the result elements in the function in that namespace and then obviously fn:node-groups(.)/group will not select them as it selects a group element in no namespace. So make sure your function overrides that namespace with <xsl:for-each-group select="$nodeRefs" group-adjacent="@class" xmlns="">.

Another reason could be that your stylesheet defines xpath-default-namespace.

I also think that your third variable needs to be <xsl:variable name="test3" select="mf:node-groups(.)/node"/> as obviously the node sequence returned by your function already is a sequence of group elements, if you want to filter that sequence then use <xsl:variable name="test3" select="fn:node-groups(.)[@class = 'heading']"/>

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! The problem was as of course that I needed to select fn:node-groups(.)/[@class = 'heading'] instead of fn:node-groups(.)/group[@class = 'heading']. Sometimes you get stuck and need a nudge in the right direction to be able to go on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.