【问题标题】:XSLT lookup from external xml file从外部 xml 文件中查找 XSLT
【发布时间】:2020-03-07 14:36:39
【问题描述】:

我知道这里有很多关于通过 xslt 从外部 xml 文件查找的问题(和答案)。但是,我还没有完全理解关键功能的逻辑,所以我很难将其他解决方案应用到我的用例中。

我有两个 xml 文件:

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>

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>

文件通过corresp-attribute 相互引用。

我正在尝试找出一个解析 versA.xml、打印自己的文本节点然后查找相应文本的 xsl 样式表 (trans.xsl) 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>

我能做的是输出 versA.xml 的 ids 并访问 versB.xml。但是,我发现设置一个适当的键函数非常困难,该函数从 versA.xml 中获取 corresp 值以在 versB.xml

如果有人能解释如何实现这一点,我会很高兴。

出于兼容性原因,xslt 版本 1.0 将是首选。

我已经根据 cmets 中给出的建议更新了我的样式表。以下给出了所需的输出:

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

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    您需要使用xsl:key 声明一个键,给它一个您可以选择的name,使用您想要“索引”的节点的match 模式,您想要声明键,并定义具有use 属性的键值,XPath 表达式:

    <xsl:key name="ref" match="TEI/div/l" use="@id"/>
    

    要使用键,您调用key 函数,将声明键的名称作为第一个参数,键值作为第二个参数,在 XSLT 2 或更高版本中,您要搜索的文档或子树,作为第三个参数:key('ref', @corresp, document('versB.xml'))

    如果你真的受限于 XSLT 1 那么,对于两个不同的文档,由于不支持key 函数的第三个参数,你需要用for-each 切换“上下文文档”,例如:

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

    上述key 函数的两个示例用法都假设您在xsl:template match="/TEI/div/l" 的上下文中创建它们,以便@corresp 在您的主输入中选择l 元素的该属性的值。

    【讨论】:

    • 谢谢!我在上面的问题中更新了我的代码。 key 函数似乎不起作用,因为它输出一个空字符串。
    • @AlexW.,查看编辑,似乎我误解了这种关系,如果第一个文档中的corresp 指的是第二个文档中的id,那么use 中的属性密钥声明必须是use="@id"
    • 只是增加另一个困难(与我的用例相关):&lt;l&gt;&lt;/l&gt; 文本节点有时包含&lt;note&gt;&lt;/note&gt; 元素。我可以定义模板来转换主文档 (versA.xml) 中的&lt;note&gt;-元素。但是,我不知道如何将模板应用于“导入的”versB.xml
    • @AlexW.,除非&lt;xsl:apply-templates select="key('ref', $corresp)/note"/&gt;(XSLT 1,需要位于更改上下文文档的for-each 内部)或&lt;xsl:apply-templates select="key('ref', $corresp, document('versB.xml'))"/&gt;(XSLT 2 和稍后)没有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2011-09-09
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多