Tony
Tony

Reputation: 37

Using XPath Axes to Locate Same Node in Preceding Ancestor with XSLT

I'm new to XPath expressions in XSLT and have hit my head against the desk for too long. I'd like to evaluate a sibling node within the first preceding ancestor of the current node and test if that node is the same.

Here's my XML:

<item>
    <number>1.0</number>
    <category>Data</category>
    <functionality>Search Screen</functionality>
    <requirement_type>SIT</requirement_type>
    <table>Table</table>
</item>
<item>
    <number>1.1</number>
    <category>Data</category>
    <functionality>Search Screen</functionality>
    <requirement_type>SIT</requirement_type>
</item>

Here's my XSLT:

<xsl:for-each select="item">
  <xsl:if test="not(preceding-sibling::*[position()=1])">
    <xsl:value-of select="category"/>
  </xsl:if>
</xsl:for-each>

Essentially, I'm trying to test whether the <category> child node of the the second <item> node is the same as the <category> child node of the the first <item> node.

Searching similar StackOverflow questions gets me close, but just not there ....

Upvotes: 0

Views: 559

Answers (1)

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22637

Assuming a well-formed input document that has a single outermost element. Also, as you can see, I have added an id attribute to the item elements to be able to tell them apart.

XML Input

<root>
    <item id="1">
        <number>1.0</number>
        <category>Data</category>
        <functionality>Search Screen</functionality>
        <requirement_type>SIT</requirement_type>
        <table>Table</table>
    </item>
    <item id="2">
        <number>1.1</number>
        <category>Data</category>
        <functionality>Search Screen</functionality>
        <requirement_type>SIT</requirement_type>
    </item>
</root>

To find out whether the category child element of the immediately preceding sibling item element is the same, you could use

<xsl:if test="category = preceding-sibling::item[1]/category">

If the semantics should actually be different, you really need to explain this more clearly, perhaps also modifying the sample document.

XSLT Stylesheet

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

    <xsl:template match="/root">
      <result>
            <xsl:for-each select="item">
              <xsl:if test="category = preceding-sibling::item[1]/category">
                <xsl:value-of select="@id"/>
              </xsl:if>
            </xsl:for-each>
      </result>
    </xsl:template>

</xsl:transform>

XML Output

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

Try this transformation online here.


EDIT

Yes, I'm trying to group the items by category. Basically, I want to get a distinct group of items within one category.

For completeness, then, as Michael has noted, you are trying to solve a grouping problem. In XSLT 1.0, use a key and do Muenchian grouping. In XLST 2.0, use xsl:for-each-group. You'll easily find examples for both techniques.

Upvotes: 1

Related Questions