XSLT: create 'key' across multiple documents?

China☆狼群 提交于 2019-12-11 03:32:54

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!