Reputation: 91
as I understand it, the xslt function generate-id()
will return a unique id depending on the node
and its context (ancestors).
Is there a way to obtain an id which is just dependent on the node
(and its subnodes), and not its position in the document?
When using xinclude
, identical nodes can be put into multiple locations -- and hence have two different ids generated. How can I create an alphanumeric string which will be identical for each instance of a node-set which was inserted into the document via xinclude
?
So I have a file node.xml
:
<?xml version="1.0" encoding="utf-8"?>
<node name="joe"/>
And a document.xml
:
<?xml version="1.0" encoding="utf-8"?>
<document xmlns:xi="http://www.w3.org/2003/XInclude">
<container name="first">
<xi:include href="node.xml"/>
</container>
<container name="second">
<xi:include href="node.xml"/>
</container>
</document>
And a process.xslt
:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="container">
this will not be identical for different matches of the template, although the matched <node/> has the same content: '<xsl:value-of select="generate-id(node)"/>'
appending some attributes this is too simple, there might be differences deeper down the hierarchy, which should resolve in a different id: '<xsl:value-of select="node/@name"/>'
</xsl:template>
</xsl:stylesheet>
Process with xsltproc --xinclude process.xslt document.xml
. I need the same id/string for both occurrences of <node/>
, as they are identical.
Greetings
Argh. this looks remarkably similar. However, I do not want to manually concat values...? It does not easily scale in my case... Maybe I can work something out using number()
but It feels like there should be something more auto...
ps: using xsltproc, so no fancy-pancy... ;-)
Upvotes: 1
Views: 1654
Reputation: 117175
Consider the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xi="http://www.w3.org/2003/XInclude">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xi:include">
<xsl:variable name="node" select="document(@href)/*" />
<included>
<id>
<xsl:value-of select="generate-id($node)"/>
</id>
<name>
<xsl:value-of select="$node/@name"/>
</name>
</included>
</xsl:template>
</xsl:stylesheet>
When this is applied to your input example - without activating the --xinclude
option - the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns:xi="http://www.w3.org/2003/XInclude">
<container name="first">
<included>
<id>idp944</id>
<name>joe</name>
</included>
</container>
<container name="second">
<included>
<id>idp944</id>
<name>joe</name>
</included>
</container>
</document>
I believe that the way you are trying it now - executing the xinclude
first - results in the XSLT receiving the merged document where each inclusion instance is converted to an individual node-set - and the processor has no way of knowing these node-sets used to be one.
Upvotes: 0
Reputation: 163645
The two node elements are not identical. They have the same children/attributes/descendants, but they have different parents and different siblings.
The two node elements are probably deep-equal according to the XPath 2.0 definition of the deep-equal function. But the deep-equal spec is by no means the only possible way the function could be specified: read the spec and you will see any number of rules could have been defined differently. (e.g. dependencies on namespace prefixes, whitespace-only text nodes, in-scope namespaces, base URI, type annotations).
Given those caveats, there are certainly cases where it would be useful to have a function say fingerprint(node)
such that fingerprint(N) = fingerprint(M)
if and only if deep-equal(N, M)
. You could write your own function but it is not at all easy to write, and it might not be efficient.
So it would help to know why you think you need it, because there may be an easier way to solve your problem.
Upvotes: 1