Reputation: 577
Given several XML files that I will call source1.xml
that look like this for example (nodes may vary):
<root id="s1">
<title>example</title>
<p>Some body text.</p>
<div>
<ul>
<li>Some list item</li>
<li>Some list item</li>
</ul>
<p>qqwerty</p>
<p>asdfg</p>
</div>
</root>
And other files that I'll call reference1.xml
that look like this:
<root>
<div>
<ul>
<li>Some list item</li>
<li>Some list item</li>
</ul>
<p>qqwerty</p>
<p>asdfg</p>
</div>
<root>
And reference2.xml
that looks like this:
<root>
<div>
<p>Some body text.<p>
</div>
</root>
There can only be one div
element in each of these files.
To map these together I have a file that looks like this:
<references>
<input src="source1.xml" id="s1">
<reference>T:\temp\reference1.xml</reference>
<reference>T:\temp\reference2.xml</reference>
</input>
</references>
I would like to get the following:
<root id="s1">
<title>example</title>
<link href="reference2.xml"/>
<div>
<link href="reference1.xml"/>
</div>
</root>
So the idea is that I want to see the whole content of the div
node of reference.xml
can be found AS/IS in source.xml
and if so, just insert a reference to it in the source. It must a "dumb replace", if I find it, I replace it in the source, wherever the content might be, no matter of the parent element or whatever.
If only certain elements are found in the source, this is a no go, no link is created. It must be the exact same thing for a link to be created.
How do I do this with XSLT 2.0?
Right now, with the code suggested in the answer I get the following output:
<root id="s1">
<title>example</title>
<link href="reference2.xml"/>
<div>
<link href="reference1.xml"/>
<link href="reference1.xml"/>
<link href="reference1.xml"/>
</div>
</root>
Instead of :
<root id="s1">
<title>example</title>
<link href="reference2.xml"/>
<div>
<link href="reference1.xml"/>
</div>
</root>
Upvotes: 0
Views: 247
Reputation: 167716
If it is only a single element to be matched against then doing
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:param name="ref-doc-uri" select="'reference.xml'"/>
<xsl:variable name="ref-doc" select="doc($ref-doc-uri)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[deep-equal(., $ref-doc//ComponentDefinition/*)]">
<link href="{$ref-doc-uri}"/>
</xsl:template>
</xsl:stylesheet>
should suffice.
Based on your edit of the requirements I have enhanced the stylesheet as
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:variable name="main-doc-uri" select="document-uri()"/>
<xsl:param name="ref-list-doc-uri" select="'reference-list.xml'"/>
<xsl:variable name="ref-list-doc" select="doc($ref-list-doc-uri)"/>
<xsl:variable name="ref-docs" select="document($ref-list-doc/references/input[resolve-uri(@src) = $main-doc-uri]/reference)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:variable name="matched-doc" select="$ref-docs[ReusableComponent/ComponentDefinition/*[deep-equal(., current())]]"/>
<xsl:choose>
<xsl:when test="$matched-doc">
<link href="{tokenize(document-uri($matched-doc), '/')[last()]}"/>
</xsl:when>
<xsl:otherwise>
<xsl:next-match/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
where I assume that reference-list.xml
has a structure like
<references>
<input src="source1.xml">
<reference>ref1.xml</reference>
<reference>ref2.xml</reference>
</input>
</references>
I haven't tried that code with several source and reference files, however, so you need to test yourself.
If there can be different namespaces used in the reference document then perhaps using a wild card helps:
<?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"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:variable name="main-doc-uri" select="document-uri()"/>
<xsl:param name="ref-list-doc-uri" select="'reference-list.xml'"/>
<xsl:variable name="ref-list-doc" select="doc($ref-list-doc-uri)"/>
<xsl:variable name="ref-docs" select="document($ref-list-doc/references/input[resolve-uri(@src) = $main-doc-uri]/reference)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:variable name="matched-doc" select="$ref-docs[*:ReusableComponent/*:ComponentDefinition/*[deep-equal(., current())]]"/>
<xsl:choose>
<xsl:when test="$matched-doc">
<link href="{tokenize(document-uri($matched-doc), '/')[last()]}"/>
</xsl:when>
<xsl:otherwise>
<xsl:next-match/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
That way, for the input
<?xml version="1.0" encoding="UTF-8"?>
<root id="s1">
<title>example</title>
<p>Some body text.</p>
<div>
<ul>
<li>Some list item</li>
<li>Some list item</li>
</ul>
</div>
</root>
I get the output
<?xml version="1.0" encoding="UTF-8"?>
<root id="s1">
<title>example</title>
<link href="reference201605270302.xml"/>
<div>
<link href="reference201605270301.xml"/>
</div>
</root>
The documents to be loaded are selected based on a comparison of the URIs in resolve-uri(@src) = $main-doc-uri
, if you want to do that based on the id
attribute then I guess you want <xsl:variable name="ref-docs" select="document($ref-list-doc/references/input[@id = $main-doc/*/@id]/reference)"/>
with a global variable <xsl:variable name="main-doc" select="/"/>
.
Upvotes: 2