user1513023
user1513023

Reputation: 11

xslt Get nth sibling based on attribute value

I need to add an xml node to a specific location in my output document based on an attribute value and its position in the xml document.

In the example below every time a product = "111" appears, I need to get the corresponding path attribute for the sub-item where the product = "222". The caveat is: their relative positions in the document have to match. For the first product = "111", I will need the path of the first product = "222". For the second "111", I will need the path of the second product "222".

Output I need (I also add the path of the current product also, but have no issues with that):

<output>
    <product_out id="111">
        <path>b</path>
    </product_out>
    <product_out id="111">
        <path>g</path>
    </product_out>
    <product_out id="111">
        <path>i</path>
    </product_out>
</output>

my xml document.

<?xml version="1.0"?>
<order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<item product="111">
    <sub_item path="a" />
</item>
<item product="222">
    <sub_item path="b" />
</item>
<item product="333">
    <sub_item path="c" />
</item>
<item product="111">
    <sub_item path="d" />
</item>
<item product="111">
    <sub_item path="e" />
</item>
<item product="555">
    <sub_item path="f" />
</item>
<item product="222">
    <sub_item path="g" />
</item>
<item product="555">
    <sub_item path="h" />
</item>
<item product="222">
    <sub_item path="i" />
</item>
</order>

My xsl document:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="/">
<output>
    <xsl:apply-templates />
</output>
</xsl:template>

<xsl:template match="order/item">
<product_out>
    <xsl:attribute name="id"><xsl:value-of select="@product"/></xsl:attribute>

    <xsl:if test="@product = 111">
        <the_correct_sibling_position><xsl:value-of select="1+count(preceding-sibling::item[@product='111'])"/></the_correct_sibling_position>
        <path_test1><xsl:value-of select="/order/item[position()=4]/sub_item/@path"/></path_test1>
        <path_test2><xsl:value-of select="/order/item[2]/sub_item/@path"/></path_test2>
        <path_test3><xsl:value-of select="/order/item[position()=number(1+count(preceding-sibling::item[@product='111']))]/sub_item/@path"/></path_test3>
        <path_test4><xsl:value-of select="/order/item[position()=1+count(preceding-sibling::item[@product='111'])]/sub_item/@path"/></path_test4>
    </xsl:if>
    <path><xsl:value-of select="sub_item/@path[1]"/></path>
</product_out>
</xsl:template>
</xsl:stylesheet>

I can get the correct array position I need using

1+count(preceding-sibling::item[@product='111'])

which I have tested by outputting the value within the <the_correct_sibling_position> node.

I can also hard code the node position:

path_test1 always returns d
path_test2 always returns b

The next 2 tests do not output the values b, g, i like I would expect.

path_test3 always returns a
path_test4 always returns a

How do I get the path to return b, g, and i based on the position of the product nodes "111" and "222"? The preceding-sibling variable is not working like I would expect inside the path of my select statements.

Please help!

Upvotes: 0

Views: 1783

Answers (1)

user1513023
user1513023

Reputation: 11

I retested some of my previous tries and it is working now, not sure why it did not before. I added a variable and then used that inside my select statement.

variable code:

<xsl:variable name="t1"><xsl:value-of select="1+count(preceding-sibling::item[@product='111'])"/></xsl:variable>

my select statement:

        <path_test_good><xsl:value-of select="/order/item[@product='222'][position()= $t1]/sub_item/@path"/></path_test_good>

Upvotes: 1

Related Questions