Reputation: 13
I have an xml file with 000's of lines with elements that differ only by some sub-string that appears in various attributes and element content.
So i'll like to 'condense' the xml and have a stylesheet create xml on the fly by substituting known sub-strings at runtime with known substitutions. A stylesheet approach would seem to be the elegant solution to this problem given what i've read about them, but if it works i really don't mind how i get a solution.
This principal would need to be generic i.e apply to xml elements with child nodes 'n levels deep' eg
'condensed' xml could look like
<element id="11[substitute here]11">
<name>[substitute here]</name>
<settings>
<setting>
<name>[substitute here]Setting</name>
<!-- could be more elements here, n levels deep -->
</setting>
</settings>
<moreConfig>zz[substitute here]zz</moreConfig>
</element>
expanded xml, substituting '[substitute here]' with 'aaa' and then 'bbb', would then look like
<element id="11aaa11">
<name>aaa</name>
<settings>
<setting>
<name>aaaSetting</name>
<!-- could more elements here, n levels deep -->
</setting>
</settings>
<moreConfig>zzaaazz</moreConfig>
</element>
<element id="11bbb11">
<name>bbb</name>
<settings>
<setting>
<name>bbbSetting</name>
<!-- could more elements here, n levels deep -->
</setting>
</settings>
<calendar>zzbbbzz</calendar>
</element>
I'm doing this in java 6, so my understanding is if using xsl only 1.0 is supported.
Hope i've outlined the problem clearly, appreciate any help!
many thanks
Upvotes: 1
Views: 491
Reputation: 243549
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:reps>
<r>aaa</r>
<r>bbb</r>
</my:reps>
<xsl:variable name="vReps"
select="document('')/*/my:reps/r"/>
<xsl:template match="node()|@*">
<xsl:param name="pCurrentRep"/>
<xsl:copy>
<xsl:apply-templates select="node()|@*">
<xsl:with-param name="pCurrentRep" select="$pCurrentRep"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="config">
<xsl:param name="pCurrentRep"/>
<xsl:variable name="vDoc" select="."/>
<xsl:copy>
<xsl:for-each select="$vReps">
<xsl:apply-templates select="$vDoc/*">
<xsl:with-param name="pCurrentRep" select="."/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="@*[contains(., '[substitute here]')]"
priority="2">
<xsl:param name="pCurrentRep"/>
<xsl:attribute name="{name()}">
<xsl:call-template name="replace">
<xsl:with-param name="pRep" select="$pCurrentRep"/>
</xsl:call-template>
</xsl:attribute>
</xsl:template>
<xsl:template match="text()[contains(., '[substitute here]')]"
priority="2">
<xsl:param name="pCurrentRep"/>
<xsl:call-template name="replace">
<xsl:with-param name="pRep" select="$pCurrentRep"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="pText" select="."/>
<xsl:param name="pTarget" select="'[substitute here]'"/>
<xsl:param name="pRep"/>
<xsl:if test="string-length($pText) >0">
<xsl:choose>
<xsl:when test="not(contains($pText, $pTarget))">
<xsl:value-of select="$pText"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-before($pText, $pTarget)"/>
<xsl:value-of select="$pRep"/>
<xsl:call-template name="replace">
<xsl:with-param name="pText" select=
"substring-after($pText, $pTarget)"/>
<xsl:with-param name="pTarget" select="$pTarget"/>
<xsl:with-param name="pRep" select="$pRep"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<config>
<element id="11[substitute here]11">
<name>[substitute here]</name>
<settings>
<setting>
<name>[substitute here]Setting</name>
<!-- could be more elements here, n levels deep -->
</setting>
</settings>
<moreConfig>zz[substitute here]zz</moreConfig>
</element>
</config>
produces the wanted, correct result:
<config>
<element id="11aaa11">
<name>aaa</name>
<settings>
<setting>
<name>aaaSetting</name><!-- could be more elements here, n levels deep -->
</setting>
</settings>
<moreConfig>zzaaazz</moreConfig>
</element>
<element id="11bbb11">
<name>bbb</name>
<settings>
<setting>
<name>bbbSetting</name><!-- could be more elements here, n levels deep -->
</setting>
</settings>
<moreConfig>zzbbbzz</moreConfig>
</element>
</config>
Upvotes: 1