I have an xml file that I need to mostly copy 1 for 1 except for 1 node with a specific value that I need to transform. My XML looks like this:
<?xml version='1.0' encoding='UTF-8'?> <xyz:Workers xmlns:xyz="urn:com.website/xyz"> <xyz:Worker> <xyz:Effective_Change xyz:Sequence="0"> <xyz:Person_Identification xyz:isAdded="1"> <xyz:Identifier> <xyz:ID>MJ 12 34 56 Z</xyz:ID> <xyz:IdType>A Type</xyz:IdType> </xyz:Identifier> </xyz:Person_Identification> </xyz:Effective_Change> </xyz:Worker> <xyz:Worker> <xyz:Effective_Change xyz:Sequence="0"> <xyz:Person_Identification xyz:isUpdated="1"> <xyz:Identifier xyz:isUpdated="1"> <xyz:ID>JHQ123</xyz:ID> <xyz:IdType>B Type</xyz:IdType> </xyz:Identifier> <xyz:Identifier xyz:isUpdated="1"> <xyz:ID xyz:priorValue="555-55-5555">123-45-6789</xyz:ID> <xyz:IdType>C Type</xyz:IdType> </xyz:Identifier> </xyz:Person_Identification> </xyz:Effective_Change> </xyz:Worker> </xyz:Workers>
I need to take the value loaded in node xyz:ID
<xyz:ID>MJ 12 34 56 Z</xyz:ID>
And strip the white space so it looks like this:
<xyz:ID>MJ123456Z</xyz:ID>
But only when their sibling node is xyz:IdType = A Type
<xyz:IdType>A Type</xyz:IdType>
Here is the XSLT I tried. I referenced this stack overflow (Using XSLT to copy all nodes in XML, with support for special cases) but after working on it, I'm unsure if this is the right approach.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:this="urn:this-stylesheet"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xyz="urn:com.website/xyz" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="xs this">
<!--Identity template,
provides default behavior that copies all content into the output -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xyz:ID">
<xsl:copy>
<xsl:value-of select="translate(node(), ' ', '')"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This XSLT gives me the below output:
<?xml version="1.0" encoding="UTF-8"?><xyz:Workers xmlns:xyz="urn:com.website/xyz">
<xyz:Worker>
<xyz:Effective_Change xyz:Sequence="0">
<xyz:Person_Identification xyz:isAdded="1">
<xyz:Identifier>
<xyz:ID>MJ123456Z</xyz:ID>
<xyz:IdType>A Type</xyz:IdType>
</xyz:Identifier>
</xyz:Person_Identification>
</xyz:Effective_Change>
</xyz:Worker>
<xyz:Worker>
<xyz:Effective_Change xyz:Sequence="0">
<xyz:Person_Identification xyz:isUpdated="1">
<xyz:Identifier xyz:isUpdated="1">
<xyz:ID>JHQ123</xyz:ID>
<xyz:IdType>B Type</xyz:IdType>
</xyz:Identifier>
<xyz:Identifier xyz:isUpdated="1">
<xyz:ID>123-45-6789</xyz:ID>
<xyz:IdType>C Type</xyz:IdType>
</xyz:Identifier>
</xyz:Person_Identification>
</xyz:Effective_Change>
</xyz:Worker>
</xyz:Workers>
Which is close to the desired output, because it did strip the white space from the desired ID:
<xyz:ID>MJ123456Z</xyz:ID>
But, on the C Type Identifier, it is removing the data loaded in the Tag:
Before Transformation:
<xyz:ID xyz:priorValue="555-55-5555">123-45-6789</xyz:ID>
<xyz:IdType>C Type</xyz:IdType>
After transformation:
<xyz:ID>123-45-6789</xyz:ID>
<xyz:IdType>C Type</xyz:IdType>
This is an issue as I want the rest of the file to be identical except for ID's where sibling ID type = A Type.
I believe this has to do something with the template match applying itself to all of the ID nodes. I tried doing something along this logic:
<xsl:template match="xyz:Identifier[xyz:IdType='A Type']">
But had no luck. Any leads on where to start or the kind of logic I should be using would be highly appreciated.
But only when their sibling node is xyz:ID_Type = A Type
You can use a predicate on xyz:Identifier
for this. Note though that you say xyz:ID_Type
but the example has xyz:IdType
.
I'd also just match text()
so you don't have to copy or apply-templates to the attributes of xyz:ID
.
Try changing your last template to (change IdType
to ID_Type
if needed for your actual data):
<xsl:template match="xyz:Identifier[xyz:IdType='A Type']/xyz:ID/text()">
<xsl:value-of select="translate(., ' ', '')"/>
</xsl:template>