Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Edit value in specific attribute with XSLT

Tags:

xml

xslt

I'm trying to write my first XSLT. It needs to find all bind elements where the attribute ref begins with "$.root" and then insert ".newRoot". I have managed to match for the specific attribute, but I don't understand how I can get it to print an updated attribute value.

Input example XML:

<?xml version="1.0" encoding="utf-8" ?>
<top>
    <products>
        <product>
            <bind ref="$.root.other0"/>
        </product>
        <product>
            <bind ref="$.other1"/>
        </product>
        <product>
            <bind ref="$.other2"/>
        </product>
        <product>
            <bind ref="$.root.other3"/>
        </product>
    </products>
</top>

My XSL so far:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

    <xsl:template match="bind[starts-with(@ref,'$.root')]/@ref">
        <xsl:attribute name="ref">$.newRoot<xsl:value-of select="bind/@ref" /></xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

The XML I would like to produce from the input:

<?xml version="1.0" encoding="utf-8" ?>
<top>
    <products>
        <product>
            <bind ref="$.newRoot.root.other0"/>
        </product>
        <product>
            <bind ref="$.other1"/>
        </product>
        <product>
            <bind ref="$.other2"/>
        </product>
        <product>
            <bind ref="$.newRoot.root.other3"/>
        </product>
    </products>
</top>
like image 891
Björn Avatar asked Aug 12 '26 02:08

Björn


1 Answers

Instead of:

<xsl:template match="bind[starts-with(@ref,'$.root')]/@ref">
    <xsl:attribute name="ref">$.newRoot<xsl:value-of select="bind/@ref" /></xsl:attribute>
</xsl:template>

try:

<xsl:template match="bind[starts-with(@ref,'$.root')]/@ref">
    <xsl:attribute name="ref">$.newRoot.root<xsl:value-of select="substring-after(., '$.root')" /></xsl:attribute>
</xsl:template>

or (same thing in a more convenient syntax):

<xsl:template match="bind/@ref[starts-with(., '$.root')]">
    <xsl:attribute name="ref">
        <xsl:text>$.newRoot.root</xsl:text>
        <xsl:value-of select="substring-after(., '$.root')" />
    </xsl:attribute>
</xsl:template>

Note the use of . to refer to the current node. In your version, the <xsl:value-of select="bind/@ref" /> instruction selects nothing, because the ref attribute is already the current node - and it has no children.

like image 148
michael.hor257k Avatar answered Aug 17 '26 04:08

michael.hor257k



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!