问题
Following from a previous question 'xslt: select unique node via intermediate reference node?'.
Is there anyway to use a 'key' that references multiple xml documents.
Something like:
<xsl:key name="ChildByFIdAndMFId"
match="collection('file:///c:/temp/xslt?select=test*.xml')Child"
use="concat(FathersID, '+', MothersFatherID)"/>
That gives an error "The collection function is not allowed at the head of a pattern". I'm trying to reference all the matching 'child' nodes by FathersID and MothersFatherID across multiple documents to get some statistical results like sum's and counts. Being able to use a collection in the key statement looked like a good contender but either I have syntax wrong or maybe that is not possible at all?
To elaborate (based on previous xml and code)...
XML files look like:
<t>
<Children>
<Child>
<ID>1</ID>
<FathersID>100</FathersID>
<MothersFatherID>200</MothersFatherID>
<Total>2</Total>
</Child>
<Child>
<ID>2</ID>
<FathersID>100</FathersID>
<MothersFatherID>201</MothersFatherID>
<Total>3</Total>
</Child>
<Child>
<ID>3</ID>
<FathersID>100</FathersID>
<MothersFatherID>202</MothersFatherID>
<Total>5</Total>
</Child>
<Child>
<ID>4</ID>
<FathersID>100</FathersID>
<MothersFatherID>201</MothersFatherID>
<Total>3</Total>
</Child>
<Child>
<ID>5</ID>
<FathersID>101</FathersID>
<MothersFatherID>201</MothersFatherID>
<Total>4</Total>
</Child>
</Children>
<Fathers>
<Father>
<ID>100</ID>
</Father>
<Father>
<ID>101</ID>
</Father>
</Fathers>
<MothersFathers>
<MothersFather>
<ID>200</ID>
</MothersFather>
<MothersFather>
<ID>201</ID>
</MothersFather>
<MothersFather>
<ID>202</ID>
</MothersFather>
</MothersFathers>
</t>
There may be up to 30 of these files to reference, but I'm only interested in matching Child nodes for now (of which may be in the order of 3000 nodes per file) - there may well be duplicate Child nodes between files although the stats (Total) will be different.
The xslt so far:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kMFByFId" match="MothersFatherID" use="../FathersID"/>
<!--use="../FathersID"/>-->
<xsl:key name="kMFById" match="MothersFather" use="ID"/>
<xsl:key name="ChildByFIdAndMFId" match="Child"
use="concat(FathersID, '+', MothersFatherID)"/>
<xsl:template match="Children|MothersFathers|text()"/>
<xsl:template match="Father">
Father ID=<xsl:value-of select="ID"/>
<xsl:variable name="Fid" select="ID"></xsl:variable>
<xsl:apply-templates select=
"key('kMFById',
key('kMFByFId', ID)
[generate-id(..)
=
generate-id(key('ChildByFIdAndMFId',
concat(../FathersID,'+',.)
)[1]
)
]
)">
<xsl:sort select="ID" data-type="text"/>
<xsl:with-param name="Fid" select="$Fid"></xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="MothersFather">
<xsl:param name="Fid"></xsl:param>
<xsl:variable name="FidAndMid" select="concat($Fid,'+',ID)"></xsl:variable>
MothersFather ID=<xsl:value-of select="ID"/>
Sum of Total= <xsl:value-of
select="sum(key('ChildByFIdAndMFId', $FidAndMid)/Total)"/>
</xsl:template>
</xsl:stylesheet>
So this works for a single xml document - above xml gives:
Father ID=100
MothersFather ID=200
Sum of Total= 2
MothersFather ID=201
Sum of Total= 6
MothersFather ID=202
Sum of Total= 5
Father ID=101
MothersFather ID=201
Sum of Total= 4
But, if I can't use a collection in the key, how do I go about referencing all the other documents matching the child nodes for the current FatherID and MothersFatherID?
If, for example, the above xml was duplicated as is to two more files that need the data pulled from them the output would have new Sum of Total like:
Father ID=100
MothersFather ID=200
Sum of Total= 6
MothersFather ID=201
Sum of Total= 18
MothersFather ID=202
Sum of Total= 15
Father ID=101
MothersFather ID=201
Sum of Total= 12
I can see I would like to use a 'collection' so I can easily pull in all the files, but I can't see where or how. Can anyone help me please?
回答1:
As Dimitre says, key()
only searches one document. If you want to search a set of documents, it's easy enough: use $s/key(...)
where $s holds the set of documents. A set of documents might be obtained from a call to the collection() function, from a call to document() supplying a set of URIs, or by combining the result of a number of calls to doc(), for example for $x in $uri-list return doc($x)
.
来源:https://stackoverflow.com/questions/14762995/xslt-create-key-across-multiple-documents