tags:

views:

3991

answers:

6

I have an XML document, I want one of the attributes to change it's value.

First I copied everything from input to output using:

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

And now I want to change the attribute "type" in any element named "property". But I don't know how to do it. Could someone please help? Thanks!

+2  A: 

You need a template that will match your target attribute, and nothing else.

<xsl:template match='XPath/@myAttr'>
  <xsl:attribute name='myAttr'>This is the value</xsl:attribute>
</xsl:template>

This is in addition to the "copy all" you already have (and is actually always present by default in XSLT). Having a more specific match it will be used in preference.

Richard
I've tried it without the "copy all" part and it only got what was between the tags. None of the tag themselves or the attributes got copied.
tomato
@coderx: Would need to see a sample, not sure what you mean.
Richard
+4  A: 

Tested on a simple example, works fine:

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="@type[parent::property]">
  <xsl:attribute name="type">
    <xsl:value-of select="'your value here'"/>
  </xsl:attribute>
</xsl:template>

Edited to include Tomalak's suggestion.

Welbog
An alternative version would be <xsl:template match="@type[parent::property]">
Tomalak
Agreed. Your way is probably more intuitive as it matches up more logically with what the template is for.
Welbog
That's what I wanted to say in the original comment as well, but forgot to actually type it. ;-)
Tomalak
@Tomalak: Depends. I would prefer the parent/@type. But this is clearly subjective.
Richard
property/@type is better as it is more clear and understandable. Probably even more efficient (by several microseconds :) )
Dimitre Novatchev
A: 

For the following XML:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <property type="foo"/>
    <node id="1"/>
    <property type="bar">
     <sub-property/>
    </property>
</root>

I was able to get it to work with the following XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="@*|node()">
     <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
     </xsl:copy>
    </xsl:template>
    <xsl:template match="//property">
     <xsl:copy>
      <xsl:attribute name="type">
       <xsl:value-of select="@type"/>
       <xsl:text>-added</xsl:text>
      </xsl:attribute>
      <xsl:copy-of select="child::*"/>
     </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
Andrew Hare
+4  A: 

This problem has a classical solution: Using and overriding the identity template is one of the most fundamental and powerful XSLT design patterns:

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
<!--                                                     -->    
    <xsl:param name="pNewType" select="'myNewType'"/>
<!--                                                     -->    
    <xsl:template match="node()|@*">
     <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
    </xsl:template>
<!--                                                     -->    
    <xsl:template match="property/@type">
     <xsl:attribute name="type">
      <xsl:value-of select="$pNewType"/>
     </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

When applied on this XML document:

<t>
  <property>value1</property>
  <property type="old">value2</property>
</t>

the wanted result is produced:

<t>
  <property>value1</property>
  <property type="myNewType">value2</property>
</t>
Dimitre Novatchev
A: 

I had a similar case where I wanted to delete one attribute from a simple node, and couldn't figure out what axis would let me read the attribute name. In the end, all I had to do was use

@*[name(.)!='AttributeNameToDelete']

rwrobson
A: 

Hello

I have below XSLT which copies XML form source to destination.

<xsl:param name="seq" select="position()"/>
 <xsl:template match="@*|node()"> 

But position() is assigning only one value to all nodes in the output, Can some one please tell me how to generate sequence in the Rollnumber should increase with a value of 1 for every node

guest