0
votes

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

1
"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." For what purpose? it seems like you are trying to group the items by category, or get the distinct categories (same thing, really). If so, do a search for grouping (probably the most often asked question here).michael.hor257k
Yes, I'm trying to group the items by category. Basically, I want to get a distinct group of items within one category. Thanks @michael.hor257k, I'll give that search a try.Tony

1 Answers

1
votes

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.