如何使用 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-name
和 name
产生相同的值。
@michael.hor257k 对于这些键,是否可以在每个文件中映射 Wxxxx
对象,还是不能这样工作?最终,我将从每个文件中提取匹配的子节点值以匹配匹配的周数。
那我误解了你的解决方案。无论如何,使用密钥会更好。恐怕我不知道如何回答您的问题,因为我无法轻松重现该问题。一般来说,在 XSLT 1.0 中,您需要在使用密钥之前将上下文切换到目标文档。
@michael.hor257k 好的。别担心。我使用了local-name()
,因为我在搜索中偶然发现了它。但在检查时,它们是可以互换的。此上下文中的 XML 文件未使用命名空间。以上是关于如何使用 XSLT1 在链接的 XML 数据库中定位匹配节点文本?的主要内容,如果未能解决你的问题,请参考以下文章