【问题标题】:XSLT: create 'key' across multiple documents?XSLT:跨多个文档创建“密钥”?
【发布时间】:2013-01-23 15:41:22
【问题描述】:

继上一个问题“xslt: select unique node via intermediate reference node?”之后。

是否可以使用引用多个 xml 文档的“键”。

类似:

<xsl:key name="ChildByFIdAndMFId" 
    match="collection('file:///c:/temp/xslt?select=test*.xml')Child"
    use="concat(FathersID, '+', MothersFatherID)"/>

这给出了一个错误“模式的头部不允许收集函数”。 我试图在多个文档中通过 FathersID 和 MothersFatherID 引用所有匹配的“子”节点,以获得一些统计结果,如总和和计数。能够在 key 语句中使用集合看起来是一个很好的竞争者,但要么我的语法错误,要么根本不可能?

详述(基于之前的xml和代码)...

XML 文件如下所示:

<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>

可能有多达 30 个这些文件可供参考,但我现在只对匹配子节点感兴趣(其中每个文件可能有 3000 个节点) - 之间很可能有重复的子节点文件,尽管统计数据(总计)会有所不同。

到目前为止的 xslt:

    <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>    

所以这适用于单个 xml 文档 - 上面的 xml 给出:

    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

但是,如果我不能在键中使用集合,我该如何引用与当前父亲 ID 和母亲父亲 ID 的子节点匹配的所有其他文档?

例如,如果上述 xml 被复制到另外两个需要从中提取数据的文件中,则输出将具有新的总和,例如:

    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

我可以看到我想使用“集合”,这样我就可以轻松地提取所有文件,但我看不出在哪里或如何。谁能帮帮我?

【问题讨论】:

  • 关于语法,我会在集合函数和子元素之间添加一个斜线:match="collection('file:///c:/temp/xslt?select=test*.xml')/Child"。但我很怀疑即使解决了这个问题也会起作用。
  • 嗨 Lars,我已经尝试过了,但仍然给出了同样的错误 The collection("file:///c:/temp/xslt?select=test*.xml") function is not allowed at the head of a pattern。干杯...
  • 一个键一次只索引一个文档。如果您想跨多个文件进行分组,请使用:&lt;xsl:for-each-group select="yourSequenceFromMultipleDocuments"&gt;
  • 谢谢 Dimitre,我现在就来看看如何使用 'for-each-group' 看看我的进展如何......
  • 嗨,Dimitre,在我的情况下,我在为每个组进行锻炼时遇到了麻烦,然后看到了我喜欢的 Michaels 的回答。干杯,布莱斯。

标签: xslt xslt-2.0


【解决方案1】:

正如 Dimitre 所说,key() 只搜索一个文档。如果要搜索一组文档,这很简单:使用 $s/key(...) 其中 $s 保存一组文档。可以通过调用 collection() 函数、通过调用提供一组 URI 的 document() 或通过组合多次调用 doc() 的结果来获得一组文档,例如 for $x in $uri-list return doc($x) .

【讨论】:

  • 嗨,Michael,我尝试使用您在集合中显示的 $s/key(...) 语法。但是,当我尝试使用 &lt;xsl:value-of select="$s/key(ChildByFIdAndMFId, $FidAndMid)"&gt; 引用密钥时,我收到错误“不允许空序列作为 key() 的第一个参数”。这是否意味着该密钥尚未索引(或其他任何功能)我尝试将其应用于的其他文档? $s 在我的调试器中显示了三个&lt;#document/fragment&gt;。你能看出我在这个计划中缺少什么来使它发挥作用吗?我是否必须事先以某种方式针对集合列表初始化我的密钥?谢谢,布莱斯。
  • @user1840734,key()的第一个参数是ChildByFIdAndMFId。这个参数应该是键名,一个字符串。由于它周围没有引号,因此它被解释为子元素的名称——它可能不存在,因此出现“空序列”错误。试试$s/key('ChildByFIdAndMFId', $FidAndMid)
  • 天啊!有些日子太愚蠢了......无论如何,喜欢你的答案 - 很容易看到现在代码中发生了什么,只有一行,没有for-each-group循环。干杯,布莱斯。
猜你喜欢
  • 2016-12-11
  • 2019-05-20
  • 1970-01-01
  • 2020-06-21
  • 2021-05-10
  • 1970-01-01
  • 2018-03-12
  • 1970-01-01
  • 2013-03-02
相关资源
最近更新 更多