user1489615
user1489615

Reputation: 31

How do I append an XML attribute using XSLT

If I have an XML that looks like this:

<Component Id="cmp25217AE65B163B199EDDA7F29198730A" Guid="{DEB29383-8BF1-4FD0-830B-DF8639F4069A}">
<Component Id="cmp93E1B1FFA5A62A43251E23BD65FBAA66" Guid="{76E8B8CE-835D-498E-9330-CE940C9510BF}">
<Component Id="cmp3D7B898C57056B0E87C3A964112BB9D6" Guid="{3BA9A892-C44F-4B2E-B0B9-B732120D35DB}">

How do I us XSLT to append 'Win64="yes"' to the end of each element like this:

<Component Id="cmp25217AE65B163B199EDDA7F29198730A" Guid="{DEB29383-8BF1-4FD0-830B-DF8639F4069A}" Win64="yes">
<Component Id="cmp93E1B1FFA5A62A43251E23BD65FBAA66" Guid="{76E8B8CE-835D-498E-9330-CE940C9510BF}" Win64="yes">
<Component Id="cmp3D7B898C57056B0E87C3A964112BB9D6" Guid="{3BA9A892-C44F-4B2E-B0B9-B732120D35DB}" Win64="yes">

Upvotes: 3

Views: 276

Answers (3)

O. R. Mapper
O. R. Mapper

Reputation: 20731

You can use the <xsl:attribute> element and apply it directly to (inside) the <xsl:copy> element:

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

Update: Embedded in an XSLT that otherwise copies the Xml contents, this looks like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

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

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

</xsl:stylesheet>

Update 2: This assumes you only want to add Win64="yes" to <Component> elements. If this is not the case, you will have to adapt the XPath expression of the match attribute in the template that inserts your additional attribute.

Update 3: Well-formed input and output documents:

I assume this as the input document:

<?xml version="1.0" encoding="UTF-8"?>
<xml>
    <Component Id="cmp25217AE65B163B199EDDA7F29198730A" Guid="{DEB29383-8BF1-4FD0-830B-DF8639F4069A}"/>
    <Component Id="cmp93E1B1FFA5A62A43251E23BD65FBAA66" Guid="{76E8B8CE-835D-498E-9330-CE940C9510BF}"/>
    <Component Id="cmp3D7B898C57056B0E87C3A964112BB9D6" Guid="{3BA9A892-C44F-4B2E-B0B9-B732120D35DB}"/>
</xml>

Then, the output of the aforementioned XSLT looks like this:

<?xml version="1.0" encoding="utf-8"?>
<xml>
  <Component Win64="yes" Id="cmp25217AE65B163B199EDDA7F29198730A" Guid="{DEB29383-8BF1-4FD0-830B-DF8639F4069A}" />
  <Component Win64="yes" Id="cmp93E1B1FFA5A62A43251E23BD65FBAA66" Guid="{76E8B8CE-835D-498E-9330-CE940C9510BF}" />
  <Component Win64="yes" Id="cmp3D7B898C57056B0E87C3A964112BB9D6" Guid="{3BA9A892-C44F-4B2E-B0B9-B732120D35DB}" />
</xml>

Upvotes: 2

Daniel Haley
Daniel Haley

Reputation: 52858

This stylesheet will add the attribute to all elements like you requested. Note that the position of the attribute might not be at the end, but that shouldn't matter.

XML Input (well-formed)

<doc>
    <Component Id="cmp25217AE65B163B199EDDA7F29198730A" Guid="{DEB29383-8BF1-4FD0-830B-DF8639F4069A}"/>
    <Component Id="cmp93E1B1FFA5A62A43251E23BD65FBAA66" Guid="{76E8B8CE-835D-498E-9330-CE940C9510BF}"/>
    <Component Id="cmp3D7B898C57056B0E87C3A964112BB9D6" Guid="{3BA9A892-C44F-4B2E-B0B9-B732120D35DB}"/>
</doc>

XSLT 1.0 (tested with Xalan and Saxon 6.5.5)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

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

</xsl:stylesheet>

Output

<doc Win64="yes">
   <Component Win64="yes" Id="cmp25217AE65B163B199EDDA7F29198730A" Guid="{DEB29383-8BF1-4FD0-830B-DF8639F4069A}"/>
   <Component Win64="yes" Id="cmp93E1B1FFA5A62A43251E23BD65FBAA66" Guid="{76E8B8CE-835D-498E-9330-CE940C9510BF}"/>
   <Component Win64="yes" Id="cmp3D7B898C57056B0E87C3A964112BB9D6" Guid="{3BA9A892-C44F-4B2E-B0B9-B732120D35DB}"/>
</doc>

Upvotes: 0

Steve H.
Steve H.

Reputation: 6947

Unfortunately, you can't use <xsl:copy> and add more attributes. I did it like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"     xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/root">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="Component">
            <xsl:element name="Component">
                <xsl:attribute name="Id" select="@Id"/>
                <xsl:attribute name="Guid" select="@Guid"/>
                <xsl:attribute name="Win64" select="'yes'"/>
            </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Upvotes: -1

Related Questions