Populate Attribute and values to all parent nodes

2019-07-21 11:59发布

问题:

I am new to XSLT and would like to add Attribute and Value of the same to all parent nodes starting from 2nd parent node. here the logic should be the if there is Main node, the attribute(Mainattribute) should be one time and for rest of all parent nodes under the Main node should have different attribute(childattribute) which should be same across all other than Main node.

we have a input xml like below : It is just have some fields only, ideally there will be more tags and may differ.

            <?xml version="1.0" encoding="UTF-8"?>
            <Header>
                <Main>
                    <Parent2>
                        <status>12</status>
                        <statusmsg>Helo</status_text>
                    </Parent2>
                    <Parent3>
                        <Child1>112</Child1>
                        <Child2>Hai</Child2>
                    </Parent3>
                    <Parent4>
                        <Child3>Valley</Child3>
                        <Parent5>
                            <Child7>Kind</Child1>
                            <Child8>Pls</Child2>
                        </Parent5>
                    </Parent4>
                </Main>
            </Header>

The output should be like below:

        <?xml version="1.0" encoding="UTF-8"?>
        <Header>
            <Main Mainattribute="1">
                <Parent2 childattribute="1">
                    <status>12</status>
                    <statusmsg>Helo</status_text>
                </Parent2>
                <Parent3 childattribute="1">
                    <Child1>112</Child1>
                    <Child2>Hai</Child2>
                </Parent3>
                <Parent4 childattribute="1">
                    <Child3>Valley</Child3>
                    <Parent5 childattribute="1">
                        <Child7>Kind</Child1>
                        <Child8>Pls</Child2>
                    </Parent5>
                </Parent4>
            </Main>
        </Header>

Can some one please share XSLT for the same. i have tried so many cases but not able to achieve it. thank you

Below is the XSLT tried for first Main node, but somehow getting error and couldnt proceed further.

        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:output indent="yes"/>
            <!-- Template to copy all the elements -->
            <xsl:template match="@*|node()">
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:template>

            <xsl:template match="Main">
                <Main>
                    <xsl:attribute name="Mainattribute">
                        <xsl:value-of select="1"/>
                    </xsl:attribute>
                    <xsl:apply-templates select="child::node()"/>
                </Main>
            </xsl:template>



        </xsl:stylesheet>

回答1:

Enhancing @Aniket V's answer, you can resort to modes instead of depending on the name of the tag:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="Main">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:attribute name="Mainattribute"><xsl:value-of select="1"/></xsl:attribute>
            <xsl:apply-templates mode="parent_mode"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*" mode="parent_mode">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:attribute name="childattribute"><xsl:value-of select="1"/></xsl:attribute>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Update

If you waht to update all XML elements which have children (but not the top level element), then this transformation is yours:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="Main" priority="1">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:attribute name="Mainattribute"><xsl:value-of select="1"/></xsl:attribute>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[child::* and ancestor::*]">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:attribute name="childattribute"><xsl:value-of select="1"/></xsl:attribute>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>


回答2:

You are quite close with the XSLT changes. Please modify the templates as below.

Template for <Main>

<xsl:template match="Main">
    <xsl:copy>
        <xsl:attribute name="Mainattribute">
            <xsl:value-of select="1" />
        </xsl:attribute>
        <xsl:apply-templates />
    </xsl:copy>
</xsl:template>

Template for nodes having name Parent.

<xsl:template match="*[contains(name(), 'Parent')]">
    <xsl:copy>
        <xsl:attribute name="childattribute">
            <xsl:value-of select="1" />
        </xsl:attribute>
        <xsl:apply-templates />
    </xsl:copy>
</xsl:template>