Reputation: 9263
I'm trying to process to xml
files (docbook
documents). There are repeating structures in the document that I would extract from both documents, parameterize, and store in a separate document.
To get it simplified, here is an example:
file1.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<input>
<structure>foo</structure>
<structure>bar</structure>
<structure>baz</structure>
</input>
file2.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<input>
<structure>abc</structure>
<structure>xyz</structure>
<structure>123</structure>
</input>
And this is the preferred output, I would like to generate.
output.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<structure origin="doc1">foo</structure>
<structure origin="doc1">bar</structure>
<structure origin="doc1">baz</structure>
<structure origin="doc2">abc</structure>
<structure origin="doc2">xyz</structure>
<structure origin="doc2">123</structure>
</output>
Now I don't know how to convert two or more documents (URI can be hard coded) and one additional parameter (doc1, doc2 - these can also be hard coded) in XSLT.
I would be very grateful for any hints.
Upvotes: 2
Views: 264
Reputation: 66723
Whether you transform file1.xml
and only read file2.xml
with fn:doc()
, or set both parameters and read both is a matter of choice, but the concept applies either way. Once you have both docs loaded, you can XPath to the /input/structure
and then apply-templates.
With XSLT 2.0, you can obtain the base-uri()
and parse that for the filename to use in the @origin
:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="fn">
<xsl:output indent="yes" />
<xsl:param name="file1" select="'file1.xml'" />
<xsl:param name="file2" select="'file2.xml'" />
<xsl:template match="/">
<output>
<xsl:apply-templates select="(fn:doc($file1) | fn:doc($file2))/input/structure"/>
</output>
</xsl:template>
<xsl:template match="structure">
<xsl:copy>
<xsl:attribute name="origin" select="concat('doc', replace(base-uri(), '.*(\d+).xml', '$1'))"/>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If you need XSLT 1.0, you could send the filename as a param:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="fn">
<xsl:output indent="yes" />
<xsl:param name="file1" select="'file1.xml'" />
<xsl:param name="file2" select="'file2.xml'" />
<xsl:template match="/">
<output>
<xsl:call-template name="load-file">
<xsl:with-param name="file" select="$file1"/>
</xsl:call-template>
<xsl:call-template name="load-file">
<xsl:with-param name="file" select="$file2"/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="load-file">
<xsl:param name="file"/>
<xsl:apply-templates select="doc($file)/input/structure">
<xsl:with-param name="file" select="$file"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="structure">
<xsl:param name="file"/>
<xsl:copy>
<xsl:attribute name="origin">
<xsl:value-of select="concat('doc', substring-after(substring-before($file, '.xml'), 'file'))"/>
</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2