xml - How to merge elements between two documents using XSLT 2.0? -
i have default configuration items in xml document follows:
<programconfig> <fragment xml:lang="en" name="targetsector">fragment/target_sector.xdp</fragment> <fragment xml:lang="fr" name="targetsector">fragment/target_sector_fr.xdp</fragment> <mastertemplate xml:lang="en">master/default_en.xdp</mastertemplate> <mastertemplate xml:lang="fr">master/default_fr.xdp</mastertemplate> </programconfig>
specific programs can override default configuration, example:
<programconfig> <fragment xml:lang="en" name="targetsector">fragment/1-5abq/target_sector.xdp</fragment> <mastertemplate xml:lang="fr">master/default_fr_1-5abq.xdp</mastertemplate> </programconfig>
i need merge xml documents, output becomes:
<programconfig> <fragment xml:lang="en" name="targetsector">fragment/1-5abq/target_sector.xdp</fragment> <fragment xml:lang="fr" name="targetsector">fragment/target_sector_fr.xdp</fragment> <mastertemplate xml:lang="en">master/default_en.xdp</mastertemplate> <mastertemplate xml:lang="fr">master/default_fr_1-5abq.xdp</mastertemplate> </programconfig>
if program specific xml has element same name , matching attributes default xml, should replace value in output document.
the xml pretty flat - set of elements under programconfig root no further child elements. each element defines file system path asset.
is there way using xslt. tried using document function, i'm not sure how match against element , attributes.
using xslt 3.0 solve using for-each-group
composite grouping key using node name , attributes:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns:xs="http://www.w3.org/2001/xmlschema" xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math" version="3.0"> <xsl:output indent="yes"/> <xsl:template name="xsl:initial-template"> <programconfig> <xsl:for-each-group select="doc('defaultconfig.xml')/programconfig/*, doc('overrideconfig.xml')/programconfig/*" group-by="node-name(.), sort(@*, function($a) { name($a) })" composite="yes"> <xsl:copy-of select="if (current-group()[2]) current-group()[2] else current-group()[1]"/> </xsl:for-each-group> </programconfig> </xsl:template> </xsl:stylesheet>
with xslt 2.0 bit more difficult construct single grouping key based on name , attribute values:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns:xs="http://www.w3.org/2001/xmlschema" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:mf="http://example.com/mf" exclude-result-prefixes="xs math mf" version="2.0"> <xsl:output indent="yes"/> <xsl:function name="mf:sort" as="node()*"> <xsl:param name="input-nodes" as="node()*"/> <xsl:perform-sort select="$input-nodes"> <xsl:sort select="name()"/> </xsl:perform-sort> </xsl:function> <xsl:template name="main"> <programconfig> <xsl:for-each-group select="doc('defaultconfig.xml')/programconfig/*, doc('overrideconfig.xml')/programconfig/*" group-by="string-join((string(node-name(.)), mf:sort(@*)), '|')"> <xsl:copy-of select="if (current-group()[2]) current-group()[2] else current-group()[1]"/> </xsl:for-each-group> </programconfig> </xsl:template> </xsl:stylesheet>
Comments
Post a Comment