I am trying to combine the content of two or more source documents into a single output document, where content should be in the same nodes.
The two source documents are Resources.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="ButtonCancelString">
<value>Cancel</value>
</data>
<data name="ButtonCloseString">
<value>Close</value>
</data>
</root>
and Resources.de.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="ButtonCancelString">
<value>Abbrechen</value>
</data>
<data name="ButtonCloseString">
<value>Schließen</value>
</data>
</root>
I use the following transformation (combine.xslt):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/empty">
<root>
<constants>
<xsl:apply-templates select="document('Resources.resx')">
<xsl:with-param name="language" select="'en'"/>
</xsl:apply-templates>
<xsl:apply-templates select="document('Resources.de.resx')">
<xsl:with-param name="language" select="'de'"/>
</xsl:apply-templates>
</constants>
</root>
</xsl:template>
<xsl:template match="/root/data">
<xsl:param name="language"/>
<xsl:element name="const">
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:element name="text">
<xsl:attribute name="lang" >
<xsl:value-of select="$language"/>
</xsl:attribute>
<xsl:value-of select="value"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
I run the transformation on an empty xml:
<?xml version="1.0" encoding="UTF-8"?>
<empty/>
The resulting document is this (some noise removed):
<root >
<constants>
<const name="ButtonCancelString">
<text lang="en">Cancel</text>
</const>
<const name="ButtonCloseString">
<text lang="en">Close</text>
</const>
<const name="ButtonCancelString">
<text lang="de">Abbrechen</text>
</const>
<const name="ButtonCloseString">
<text lang="de">Schließen</text>
</const>
</constants>
</root>
But instead of duplicate nodes, I need the following output:
<?xml version="1.0" encoding="UTF-8"?>
<root >
<constants>
<const name="ButtonCancelString">
<text lang="en">Cancel</text>
<text lang="de">Abbrechen</text>
</const>
<const name="ButtonCloseString">
<text lang="en">Close</text>
<text lang="de">Schließen</text>
</const>
</constants>
</root>
Is there a way to achieve this using transfomations?
As your stylesheet has version="2.0"
I have written an XSLT 2.0 solution, I would either use keys or for-each-group
, in the sample below I have used keys. It expects the Resources.resx
as the primary input document and a parameter with a sequence of strings of the form Resource.lang.resx
for the other documents:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="xs fn">
<xsl:param name="resource-urls" as="xs:string*" select="'Resources.de.resx', 'Resources.es.resx'"/>
<xsl:variable name="resource-docs" as="document-node()*" select="for $url in $resource-urls return doc($url)"/>
<xsl:key name="name" match="data" use="@name"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<root>
<constants>
<xsl:apply-templates select="data"/>
</constants>
</root>
</xsl:template>
<xsl:template match="/root/data">
<const name="{@name}">
<xsl:apply-templates select="., for $doc in $resource-docs return key('name', @name, $doc)" mode="value"/>
</const>
</xsl:template>
<xsl:template match="/root/data" mode="value">
<xsl:variable name="name-tokens" select="tokenize(tokenize(document-uri(/), '/')[last()], '\.')"/>
<xsl:variable name="language" as="xs:string" select="if ($name-tokens[3]) then $name-tokens[2] else 'en'"/>
<text lang="{$language}">
<xsl:value-of select="value"/>
</text>
</xsl:template>
</xsl:stylesheet>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.