I am working with xml, which I need to copy and update for further processing. The problem I am facing is that I did not find an effective method for this. Essentially, I want to update some data, conditionally, and then copy all the nodes that have not been updated. Why this is difficult is connected with the volume and dispersion of the number and name of the nodes that need to be copied. I also want to NOT copy nodes that have no text value. Here is an example:
INPUT XML
<root> <PersonProfile xmlns:'namespace'> <ID>0001</ID> <Name> <FirstName>Jonathan</FirstName> <PreferredName>John</PreferredName> <MiddleName>A</MiddleName> <LastName>Doe</LastName> </Name> <Country>US</Country> <Biirthdate>01-01-1980</Birthdate> <BirthPlace> <City>Townsville</City> <State>OR</State> <Country>US</Country> </Birthplace> <Gender>Male</Gender> <HomeState>OR</HomeState> ... <nodeN>text</nodeN> </PersonProfile> </root>
The "PersonProfile" node is just one of several sets of node inside the root element, each of which has its own subset of data. Such as mailing address, emergency contact information, etc. What I'm trying to do is update the nodes if the variable has a new value for them, and then copy all the nodes that have not been updated.
Here is my current XSLT
<xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <xsl:variable name='updateData' select='document("report")'/> <xsl:template match='@* | node()'> <xsl:if test'. != ""'> <xsl:copy> <xsl:apply-templates select='@* | node()'/> </xsl:copy> </xsl:if> </xsl:template> <xsl:template match='PersonProfile'> <xsl:copy> <xsl:apply-templates select='*'/> <xsl:element name='Name'> <xsl:if test='exists($updateData/Preferred)'> <xsl:element name='FirstName'> <xsl:value-of select='$reportData/FirstName'/> </xsl:element> </xsl:if> <xsl:if test='exists($updateData/Preferred)'> <xsl:element name='PreferredName'> <xsl:value-of select='$updateData/Preferred'/> </xsl:element> </xsl:if> <xsl:if test='exists($updateData/Middle)'> <xsl:element name='MiddleName'> <xsl:value-of select='$updateData/Middle'/> </xsl:element> </xsl:if> <xsl:if test='exists($updateData/LastName)'> <xsl:element name='LastName'> <xsl:value-of select='$updateData/wd:LastName'/> </xsl:element> </xsl:if> </xsl:element> <xsl:if test='exists($updateData/Country)'> <xsl:element name='Country'> <xsl:value-of select='$updateData/Country'/> </xsl:element> </xsl:if> .... </xsl:copy> </xsl:template> </xsl:stylesheet>
What is happening right now is that it copies ALL the nodes and then adds the update values. Using Saxon-PE 9.3.0.5, I get a similar result:
Output result
<root> <PersonProfile xmlns:'namespace'> <ID>0001</ID> <Name> <FirstName>Jonathan</FirstName> <PreferredName>John</PreferredName> <MiddleName>A</MiddleName> <LastName>Doe</LastName> </Name> <Country>US</Country> <Biirthdate>01-01-1980</Birthdate> <BirthPlace> <City>Townsville</City> <State>OR</State> <Country>US</Country> </Birthplace> <Gender>Male</Gender> <HomeState>OR</HomeState> ... <nodeN>text</nodeN> <PreferredName>Jonathan</PreferredName> <HomeState>WA</HomeState> </PersonProfile> </root>
I understand that this is happening because I apply templates to all nodes in PersonProfile and I can specify which nodes to exclude, but I feel that this is a very bad decision, because the volume of nodes can be above 30 or more, and this will require written value for each of them. I believe that XML has a more elegant solution than explicitly listing each of these nodes. I would like to have the following:
Desired Result
<root> <PersonProfile xmlns:'namespace'> <ID>0001</ID> <Name> <FirstName>Jonathan</FirstName> <PreferredName>Jonathan</PreferredName> <MiddleName>A</MiddleName> <LastName>Doe</LastName> </Name> <Country>US</Country> <Biirthdate>01-01-1980</Birthdate> <BirthPlace> <City>Townsville</City> <State>OR</State> <Country>US</Country> </Birthplace> <Gender>Male</Gender> <HomeState>WA</HomeState> ... <nodeN>text</nodeN> </PersonProfile> </root>
If anyone can help me create a template structure that will work for the xml structure, I would GREAT rate it. It should be "reused" because there are similar node structures, such as a personality profile, to which I would have to apply it, but with different node names and the number of elements, etc.
Thanks in advance for your help!