ewan.chalmers
ewan.chalmers

Reputation: 16265

XPATH Select children of a parent whose sibling matches a condition

Given this XML (simplified from the real content):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://foo.com">
<name>Project Name</name>
<namespace>
    <name>ROOT</name>
    <namespace>
        <name>A</name>
        <namespace>
            <name>AA</name>
            <subject>
                <name>SUBJECT</name>
            </subject>
            <item>
                <name>ITEM_AA1</name>
            </item>
        </namespace>
    </namespace>
    <namespace>
        <name>B</name>
        <namespace>
            <name>BB</name>
            <subject>
                <name>SUBJECT</name>
            </subject>
            <item>
                <name>ITEM_BB1</name>
            </item>
            <item>
                <name>ITEM_BB2</name>
            </item>
        </namespace>
    </namespace>
</namespace>
</project>

I am trying to create an XSL stylesheet to transform text nodes such as ITEM_BB1 and ITEM_BB2 - i.e. item/name/text() nodes which are sub-children of the namespace with a child name element which has the text content B.

I am having trouble figuring out how to make a template which correctly matches those nodes.

I have tried building an expression with ../ and with following-sibling axis, but am not getting it. Here is my WIP stylesheet:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:x="http://foo.com" 
    exclude-result-prefixes="x"
    version="1.0" >

    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>

    <xsl:template match="node()|@*">
        <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
    </xsl:template>

    <!-- THIS OPERATES ON THE RIGHT ITEMS AT LEAST, BUT OUT OF CONTEXT -->
    <!--
    <xsl:template match="x:namespace/x:name[text()='B']">
        <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
        <xsl:for-each select="..//x:item/x:name/text()">
            <hello><xsl:value-of select="."/></hello>
        </xsl:for-each>
    </xsl:template>
    -->

    <!-- THIS IS INVALID -->
    <xsl:template match="x:namespace/x:name[text()='B']/..//x:item/x:name/">
        <hello><xsl:value-of select="."/></hello>
    </xsl:template>

</xsl:stylesheet>

My question is how to make a template to match those target nodes?

Upvotes: 1

Views: 897

Answers (1)

Tim C
Tim C

Reputation: 70648

Try this template match, to avoid using the .. expression in the template

<xsl:template match="x:namespace[x:name/text()='B']//x:item/x:name">

This can be slightly simplified to this too...

<xsl:template match="x:namespace[x:name='B']//x:item/x:name">

Upvotes: 1

Related Questions