如何使用 XSLT1 在链接的 XML 数据库中定位匹配节点文本?

Posted

技术标签:

【中文标题】如何使用 XSLT1 在链接的 XML 数据库中定位匹配节点文本?【英文标题】:How to locate the match node text in a linked XML database using XSLT1? 【发布时间】:2021-11-18 10:43:20 【问题描述】:

我知道我的 XML 文件格式不好,但它就是这样。而且我仅限于 XSLT-1。

这是一些 XSLK 脚本:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msa="http://www.publictalksoftware.co.uk/msa">
    <xsl:output method="html" indent="yes" version="4.01"
      doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
      doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/>

    <xsl:variable name="EnglishDB" select="document('MWBData_ENG.XML')"/>
    <xsl:variable name="PunjabiDB" select="document('MWBData_PAN.XML')"/>
    <xsl:template match="/">
        <html>
            <head>
                <meta http-equiv="X-UA-Compatible" content="IE=edge" />
                <title>Terminology List</title>
            </head>
            <body>
                <table>
                    <xsl:apply-templates select ="$EnglishDB/MeetingWorkBook/*/WatchtowerStudyTheme"/>
                    <xsl:apply-templates select ="$PunjabiDB/MeetingWorkBook/*/WatchtowerStudyTheme"/>
                </table>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="WatchtowerStudyTheme">
        <xsl:variable name="week" select="name(..)"/>

        <tr>
            <td>
                <xsl:value-of select="name(..)"/>
            </td>
            <td>
                <xsl:value-of select="."/>
            </td>
        </tr>
    </xsl:template>

</xsl:stylesheet>

一些测试 XML:

<?xml version="1.0" encoding="UTF-8"?>
<MeetingWorkBook Version="211300">
    <W20191230>
        <WatchtowerStudyTheme>Build Strong Friendships Before the End Comes</WatchtowerStudyTheme>
    </W20191230>
    <W20200106>
        <WatchtowerStudyTheme>How Holy Spirit Helps Us</WatchtowerStudyTheme>
    </W20200106>
</MeetingWorkBook>

XML“W”节点确实有更多的子节点,但我目前只关注其中一个。

我可以将每个 XML 文件分配给一个变量($EnglishDB$PunjabiDB),我可以隔离所有英文主题并将它们显示在一个表格中。

但我想做的是在旁遮普语数据库中找到那个英语主题。

所以如果我们为英文文件显示这个节点:

$EnglishDB/MeetingWorkBook/W20191230/WatchtowerStudyTheme

那我现在也想显示:

$PunjabiDB/MeetingWorkBook/W20191230/WatchtowerStudyTheme

但我无法确定如何在 Punabi 数据库中构建合适的路径。

理想情况下,我想循环英语文件中的所有拓扑级别“W”元素,然后在旁遮普文件中找到匹配的“W”元素,这样我就可以简单地在两列中并排显示感兴趣的保存节点。

但逻辑不通。

【问题讨论】:

【参考方案1】:

考虑这个非常简化的例子:

XML

<anything/>

external.xml

<MeetingWorkBook Version="211300">
    <W20191230>
        <WatchtowerStudyTheme>Build Strong Friendships Before the End Comes</WatchtowerStudyTheme>
    </W20191230>
    <W20200106>
        <WatchtowerStudyTheme>How Holy Spirit Helps Us</WatchtowerStudyTheme>
    </W20200106>
</MeetingWorkBook>

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:param name="external-doc" select="document('external.xml')"/>

<xsl:key name="elem-by-name" match="*" use="name()" />

<xsl:template match="/">
    <xsl:variable name="week">W20200106</xsl:variable>
    <output>
        <!-- switch context to external document -->
        <xsl:for-each select="$external-doc">
            <!-- lookup from external document -->
            <xsl:value-of select="key('elem-by-name', $week)/WatchtowerStudyTheme" />
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

结果

<?xml version=1.0" encoding="UTF-8"?>
<output>How Holy Spirit Helps Us</output>

【讨论】:

谢谢。如果您想同时显示同一主题的两个结果?使用这种方法? 你永远不会“同时”做两件事。您将从一个文档中查找的值写入输出。然后创建另一个单元格,将上下文切换到另一个文档,并将从那里查找的值写入输出。 我理解你。我认为出于我的目的,我会坚持我的方法,因为无论如何它都会产生我需要的东西。【参考方案2】:

我用过local-name(),现在看来还可以:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msa="http://www.publictalksoftware.co.uk/msa">
    <xsl:output method="html" indent="yes" version="4.01"
      doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
      doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/>

    <xsl:variable name="EnglishDB" select="document('MWBData_ENG.XML')"/>
    <xsl:variable name="PunjabiDB" select="document('MWBData_PAN.XML')"/>
    <xsl:template match="/">
        <html>
            <head>
                <meta http-equiv="X-UA-Compatible" content="IE=edge" />
                <title>Terminology List</title>
            </head>
            <body>
                <table>
                    <xsl:apply-templates select ="$EnglishDB/MeetingWorkBook/*/WatchtowerStudyTheme"/>
                </table>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="WatchtowerStudyTheme">
        <xsl:variable name="week" select="name(..)"/>

        <tr>
            <td>
                <xsl:value-of select="name(..)"/>
            </td>
            <td>
                <xsl:value-of select="."/>
            </td>
            <td>
                <xsl:value-of select="$PunjabiDB/MeetingWorkBook/*[local-name() = $week]/WatchtowerStudyTheme"/>
            </td>
        </tr>
    </xsl:template>

</xsl:stylesheet>

【讨论】:

(1) 如果local-name() 返回的结果与name() 不同,则目标节点位于命名空间中——正确的解决方案是在样式表中声明相同的命名空间,为其分配前缀并使用此前缀来寻址目标节点,而不是使用像 *[local-name() = ...] 这样的 hack。 (2) 解决交叉引用的首选方法是使用key。 @michael.hor257k 实际上,local-namename 产生相同的值。 @michael.hor257k 对于这些键,是否可以在每个文件中映射 Wxxxx 对象,还是不能这样工作?最终,我将从每个文件中提取匹配的子节点值以匹配匹配的周数。 那我误解了你的解决方案。无论如何,使用密钥会更好。恐怕我不知道如何回答您的问题,因为我无法轻松重现该问题。一般来说,在 XSLT 1.0 中,您需要在使用密钥之前将上下文切换到目标文档。 @michael.hor257k 好的。别担心。我使用了local-name(),因为我在搜索中偶然发现了它。但在检查时,它们是可以互换的。此上下文中的 XML 文件未使用命名空间。

以上是关于如何使用 XSLT1 在链接的 XML 数据库中定位匹配节点文本?的主要内容,如果未能解决你的问题,请参考以下文章

XSLT 1.0:CSV 到 XML - 如何分而治之

BOS中定区关联客户

XSLT 1.0 按子节点的值对 xml 节点进行分组

XSLT1,Muenchian 分组,在 foreach 循环中列出分组节点

XSLT 1.0 / 使用条件对每个结果进行排序

XSLT 1.0 (xsltproc) - 无法解析巨大的 XML