问题
I am aware that there are plenty of questions (and answers) here on the lookup from external xml files via xslt. However, I still haven't got my head around the logic of the key function so I'm having a hard time applying other solutions to my use case.
I have two xml files:
versA.xml
<TEI>
<div>
<l id="A001" corresp="B001">First line of VersA</l>
<l id="A002" corresp="B002">Second line of VersA</l>
<l id="A003" corresp="B003">Third line of VersA</l>
</div>
</TEI>
and
versB.xml
<TEI>
<div>
<l id="B001" corresp="A001">First line of VersB</l>
<l id="B002" corresp="A002">Second line of VersB</l>
<l id="B003" corresp="A003">Third line of VersB</l>
</div>
</TEI>
The files refer to each other via the corresp-attribute.
I'm trying to figure out a xsl stylesheet (trans.xsl) that parses versA.xml, prints its own text node and then looks up the corresponding text node in versB.xml
trans.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:variable name="vB" select="document('versB.xml')/TEI/div/l"/>
<xsl:template match="/TEI/div/l">
I found ID <xsl:value-of select="@id"/> in versA.xml.
How can I get the corresponding node in versB.xml which has the ID <xsl:value-of select="@corresp"/>?
</xsl:template>
</xsl:stylesheet>
What I can do is output the ids of versA.xml and access versB.xml. I find it extremely difficult however, to set up an appropriate key function that takes the corresp value from versA.xml to look up the corresponding id in versB.xml
I'd be happy if somebody could explain how this can be achieved.
For compatibility reasons xslt version 1.0 would be preferred.
I have updated my stylesheet according to the suggestions given in the comments. The following gives the desired output:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="ref" match="TEI/div/l" use="@id"/>
<xsl:template match="/TEI/div/l">
<xsl:variable name="corresp" select="@corresp"/>
<xsl:value-of select="."/> corresponds to
<xsl:for-each select="document('versB.xml')">
<xsl:value-of select="key('ref', $corresp)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
回答1:
You need to declare a key with xsl:key, giving it a name you can choose, using a match pattern of the nodes you want to "index", you want to declare the key for, and defining a key value with the use attribute, an XPath expression:
<xsl:key name="ref" match="TEI/div/l" use="@id"/>
To use a key you call the key function with the name of the declared key as the first argument, the key value as the second argument and, in XSLT 2 or later, the document or subtree you want to search, as the third argument: key('ref', @corresp, document('versB.xml')).
If you are really restricted to XSLT 1 then, with two different documents, as the third argument of the key function is not supported, you need to switch the "context document" with for-each, for instance:
<!-- need to store value of main input document we want to lookup in variable -->
<xsl:variable name="corresp" select="@corresp"/>
<!-- now we change the context document to be able to apply the key function on secondary input -->
<xsl:for-each select="document('versB.xml')">
<xsl:value-of select="key('ref', $corresp)"/>
</xsl:for-each>
Both example uses of the key function above assume you make them in the context of an xsl:template match="/TEI/div/l" so that @corresp selects the value of that attribute of an l element in your main input.
来源:https://stackoverflow.com/questions/60578625/xslt-lookup-from-external-xml-file