Reputation: 85
So I know how to find a node based upon one of it's child values, but how would I go about finding an xml node by one child value, then changing another child value of that node accordingly. i.e. if I wanted to find a dog node by it's name tag, then change it's breed tag.
<dog>
<name>Fido</name>
<breed>GSD</breed>
</dog>
should become:
<dog>
<name>Fido</name>
<breed>Labrador</breed>
</dog>
Thanks, Adam
Upvotes: 0
Views: 849
Reputation: 85
So from taking Daniel's answer and running with it, this is ultimately what gave me the best solution. (I am paraphrasing the code for obvious reasons but it should suffice). I am still saying that Daniel's answer will work because in most situations it will be fine but I ended up needing a way to handle additional options that I was unaware of when creating the question.
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="../dog[name = $dog.variable.name]:>
<xsl:copy-of select="."/>
<xsl:copy-of select="optionalParams"/>
.
.
.
<breed>Labrador</breed>
</xsl:template>
Upvotes: 0
Reputation: 52888
Normally you could just match the breed
in the dog
with the name
"Fido" like this...
<xsl:template match="dog[name='Fido']/breed">
<breed>Labrador</breed>
</xsl:template>
But you said in a comment:
how would it handle doing that if say the name was a variable passed in through xsltproc?
In XSLT 1.0 you can't reference a variable or parameter in a match
statement. You would need to use an xsl:choose
to check the name
(updated to also pass the breed in as an xsl:param, but it's not strictly necessary)...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="animalName" select="'Fido'"/>
<xsl:param name="animalBreed" select="'Labrador'"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="breed">
<xsl:choose>
<xsl:when test="../name=$animalName">
<breed><xsl:value-of select="$animalBreed"/></breed>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
In XSLT 2.0 you could just change the match to dog[name=$animalName]/breed
.
Upvotes: 1
Reputation: 29052
You can use an identity template and a replacement template replacing specific <breed>
elements:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<!-- identity template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<!-- replaces <breed> elements with specific text content -->
<xsl:template match="breed[text()='GSD' and parent::dog[name='Fido']]">
<breed>Labrador</breed>
</xsl:template>
</xsl:stylesheet>
Output:
<dog>
<name>Fido</name>
<breed>Labrador</breed>
</dog>
Upvotes: 1