I want to update some nodes in XML using XSLT. Like contact detail and Email. Currently I am using command like:
<xsl:template match="@*|node()*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/Metadata/contact/node/Email">
<xsl:variable name="OName" select="/Metadata/contact/organisationName/CharacterString"/>
<xsl:variable name="Email" select="/Metadata/contact/node/Email/CharacterString"/>
<xsl:choose>
<xsl:when test="contains($OName,'TestOrg')">
<CharacterString>
<xsl:value-of select="'test@Test.com'"/>
</CharacterString>
</xsl:when>
<xsl:otherwise>
<CharacterString>
<xsl:value-of select="$Email"/>
</CharacterString>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
As Contact nodes are multiple and in each Contact node there are one organizaion name and email id. For ex of contact nodes are 3 and currently it fetch 3 values in $OName variable and $Email variable so nodes are not match. So how can I update only some nodes in xml using XSLT?
The very first template you have is a so called "Identity template" and will loop through your complete source XML:
<xsl:template match="@*|node()*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
The second template you have will match on every /Metadata/contact/node/Email
. I would write this template a little bit different. Instead of matching the absolute path, I think it is best to match the Email/CharacterString
node and then perform your actions.
I would use a template like:
<xsl:template match="Email/CharacterString">
<xsl:copy>
<xsl:choose>
<xsl:when test="contains(ancestor::contact/organisationName/CharacterString,'TestOrg')">
<xsl:value-of select="'test@Test.com'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
Above template only matches the node you want to change (being Email/CharacterString
). Once matches the xsl:copy
copies the current selected node (CharacterString
). The value will be filled depending on the value of ancestor::contact/organisationName/CharacterString
. I am using the XPath Axe ancestor
overhere. Which will be handy when changing the template.
If I would now change the template, for example only select the contact nodes that I would like to change, the second template can be written as:
<xsl:template match="contact[organisationRole/CharacterString = '1']/node/Email/CharacterString">
<xsl:copy>
<xsl:choose>
<xsl:when test="contains(ancestor::contact/organisationName/CharacterString,'TestOrg')">
<xsl:value-of select="'test@Test.com'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
Here I only apply the template to contact
nodes where ([]
) the organisationRole/CharacterString
equals the value 1. Note that the body of the template did not change. Therefore you can see why the use of the XPath Axe is usefull.
Complete XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- Identity template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="contact[organisationRole/CharacterString = '1']/node/Email/CharacterString">
<xsl:copy>
<xsl:choose>
<xsl:when test="contains(ancestor::contact/organisationName/CharacterString,'TestOrg')">
<xsl:value-of select="'test@Test.com'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Source XML
<?xml version="1.0" encoding="UTF-8"?>
<Metadata>
<contact>
<organisationRole>
<CharacterString>1</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>TestOrg</CharacterString>
</organisationName>
<postalCode>
<CharacterString>2020</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>some@user.com</CharacterString>
</Email>
</node>
</contact>
<contact>
<organisationRole>
<CharacterString>2</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>Example Org</CharacterString>
</organisationName>
<postalCode>
<CharacterString>8080</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>somebody@else.com</CharacterString>
</Email>
</node>
</contact>
<contact>
<organisationRole>
<CharacterString>1</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>Real Org</CharacterString>
</organisationName>
<postalCode>
<CharacterString>9050</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>user@example.com</CharacterString>
</Email>
</node>
</contact>
</Metadata>
Produced output
<?xml version="1.0" encoding="UTF-8"?>
<Metadata>
<contact>
<organisationRole>
<CharacterString>1</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>TestOrg</CharacterString>
</organisationName>
<postalCode>
<CharacterString>2020</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>test@Test.com</CharacterString>
</Email>
</node>
</contact>
<contact>
<organisationRole>
<CharacterString>2</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>Example Org</CharacterString>
</organisationName>
<postalCode>
<CharacterString>8080</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>somebody@else.com</CharacterString>
</Email>
</node>
</contact>
<contact>
<organisationRole>
<CharacterString>1</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>Real Org</CharacterString>
</organisationName>
<postalCode>
<CharacterString>9050</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>user@example.com</CharacterString>
</Email>
</node>
</contact>
</Metadata>
EDIT
If you only want to change the Email/CharacterString
from the contacts where the organisationName/CharacterString
contains the text TestOrg
the XSLT would look like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- Identity template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="contact[contains(organisationName/CharacterString,'TestOrg')]/node/Email/CharacterString">
<xsl:copy>
<xsl:value-of select="'test@Test.com'"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>