I am relatively new to XSLT so I am still trying to figure out how to move
from a procedural to functional mindset.
I have an XML file that I need to parameterize by replacing certain values
within tags with a placeholder.
This modified XML file will be sent to an external tool that will fill in
values for the placeholder at the appropriate time.
I would like to convert the first xml file below to the second one. The
placeholders are written in () with a variable name in between.
Source File:
<Document>
<Header>
<ID>12345</ID>
</Header>
<Body>
<Status>
<Command>Test</Command>
<Reference>11</Reference>
</Status>
<Status>
<Command>Add</Command>
<Reference>67</Reference>
</Status>
<Map>
<MapItem>
<Target>
<Loc>67</Loc>
</Target>
</MapItem>
</Map>
<Status>
<Command>Test</Command>
<Reference>22</Reference>
</Status>
<Status>
<Command>Add</Command>
<Reference>89</Reference>
</Status>
<Map>
<MapItem>
<Target>
<Loc>89</Loc>
</Target>
</MapItem>
</Map>
</Body>
</Document>
Desired Output:
<Document>
<Header>
<ID>(id)</ID>
</Header>
<Body>
<Status>
<Command>Test</Command>
<Reference>11</Reference>
</Status>
<Status>
<Command>Add</Command>
<Reference>(ref1)</Reference>
</Status>
<Map>
<MapItem>
<Target>
<Loc>(ref1)</Loc>
</Target>
</MapItem>
</Map>
<Status>
<Command>Test</Command>
<Reference>22</Reference>
</Status>
<Status>
<Command>Add</Command>
<Reference>(ref2)</Reference>
</Status>
<Map>
<MapItem>
<Target>
<Loc>(ref2)</Loc>
</Target>
</MapItem>
</Map>
</Body>
</Document>
My XSL file simply copies everything from the source to the output until it
finds a node that matches a place that needs to be paramaterized, and
replaces that tag with the parameter. But the transform currently falls
short in 2 areas:
1. It can place the placeholder in the //Status/Reference node if it has a
sibling of Command=Add but I cannot figure out a way of adding an index
number to the placeholder that increases sequentially for each match. Both
position() and <xsl:number > do not work with the transform constructed
this way.
2. How can I use the same placeholder in the //Map/MapItem/Target/Loc if
infact the number matches the one in the //Status/Reference tag above it.
If I could create a static counter that only got incremented when the
appropriate node in the file was found it would work but since XSLT does
not allow updating of variables I am not sure how to restructure the
transform to effectively do this.
If anyone has had to do a similar type of transform or has some pointers on
how to restructure the XSL file to do this I would appreciate any insight
you could provide.
Transform:
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" encoding="iso-8859-1" indent="no"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//Header/ID">
<ID><xsl:copy-of select="@*" />(id)</ID>
</xsl:template>
<xsl:template match="//Body/Status/Reference">
<xsl:choose>
<xsl:when test="preceding-sibling::Command='Add'">
<Reference><xsl:copy-of select="@*"
/>(ref)</Reference>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Thanks in advance,
Scott
"The universe is driven by the complex interaction between three
ingredients: matter, energy, and enlightened self-interest."
- G'Kar, Survivors
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list