XSLT - 在多个文件时选择唯一元素
Posted
技术标签:
【中文标题】XSLT - 在多个文件时选择唯一元素【英文标题】:XSLT - Selecting unique elements when multiple files 【发布时间】:2022-01-05 19:38:12 【问题描述】:我不知道如何通过 xsltproc 使用两个文件来完成这项工作。 Cooking.xml 使用 document() 打开,menu.xml 在命令行中传入。我可以毫无问题地选择食谱,但我不知道如何获得一份独特的配料清单。当我在我的成分列表中使用前面的兄弟函数时,它的行为类似于 [shell, beef, lettuce,tomato, cheese], [eggs, cheese]。为什么像“cooking/recipe[@name = $menu]/ingredients”这样的选择会创建一个我不能使用previous-sibling的不相交集?
这是一个来自更大系统的人为示例。
文件cooking.xml
<?xml version="1.0" encoding="UTF-8"?>
<cooking xmlns="https://cooking.com/2022/cooking">
<recipe name="tacos">
<ingredient name="shell"/>
<ingredient name="beef"/>
<ingredient name="lettuce"/>
<ingredient name="tomato"/>
<ingredient name="cheese"/>
</recipe>
<recipe name="hamburger">
<ingredient name="bun"/>
<ingredient name="beef"/>
<ingredient name="lettuce"/>
<ingredient name="tomato"/>
</recipe>
<recipe name="omelet">
<ingredient name="eggs"/>
<ingredient name="cheese"/>
</recipe>
<recipe name="soup">
<ingredient name="chicken"/>
<ingredient name="stock"/>
</recipe>
</cooking>
文件 menu.xml
<?xml version="1.0" encoding="UTF-8"?>
<cooking xmlns="https://cooking.com/2022/cooking">
<recipe name="tacos"/>
<recipe name="omelet"/>
</cooking>
文件 shop.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:set="http://exslt.org/sets"
xmlns:cook="https://cooking.com/2022/cooking"
extension-element-prefixes="set">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:key name="rcp" match="recipe" use="@name" />
<xsl:template match="cooking">
<output>
<xsl:variable name="menu" select="recipe/@name" />
<!-- switch context to target document in order to use key -->
<xsl:for-each select="document('cooking.xml')">
<xsl:for-each select="set:distinct(key('rcp', $menu)/ingredient/@name)">
<ingredient name="."/>
</xsl:for-each>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
xsltproc shop.xsl menu.xml >ingredients.xml
<?xml version="1.0" encoding="UTF-8"?>
<output xmlns:cook="https://cooking.com/2022/cooking"/>
期望的输出:
<?xml version="1.0" encoding="UTF-8"?>
<cooking xmlns:cook="https://cooking.com/2022/cooking">
<ingredient name="shell"/>
<ingredient name="beef"/>
<ingredient name="lettuce"/>
<ingredient name="tomato"/>
<ingredient name="cheese"/>
<ingredient name="eggs"/>
</cooking>
【问题讨论】:
那么最小但完整的 XSLT 代码以及确切的不需要的结果示例和想要的结果示例在哪里? 【参考方案1】:为什么像“cooking/recipe[@name = $menu]/ingredients”这样的选择会创建一个我不能使用previous-sibling的不相交集?
因为preceding-sibling
轴是在输入树的上下文中评估的,而不是在您选择的上下文中。如果您将选择复制到变量中,情况会有所不同。
无论哪种方式,使用preceding-sibling
轴都不是选择唯一值的好方法。如果您使用的是xsltproc
(即libxslt
),那么您可以执行以下操作:
XSLT 1.0 + EXSLT 设置:distinct-values()
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:set="http://exslt.org/sets"
extension-element-prefixes="set">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/cooking">
<output>
<xsl:for-each select="set:distinct(document('cooking.xml')/cooking/recipe[@name = current()/recipe/@name]/ingredient/@name)">
<ingredient name="."/>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
或者效率更高一点:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:set="http://exslt.org/sets"
extension-element-prefixes="set">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:key name="rcp" match="recipe" use="@name" />
<xsl:template match="/cooking">
<output>
<xsl:variable name="menu" select="recipe/@name" />
<!-- switch context to target document in order to use key -->
<xsl:for-each select="document('cooking.xml')">
<xsl:for-each select="set:distinct(key('rcp', $menu)/ingredient/@name)">
<ingredient name="."/>
</xsl:for-each>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
得到:
结果
<?xml version="1.0" encoding="UTF-8"?>
<output>
<ingredient name="shell"/>
<ingredient name="beef"/>
<ingredient name="lettuce"/>
<ingredient name="tomato"/>
<ingredient name="cheese"/>
<ingredient name="eggs"/>
</output>
但是对于这个cooking.xml
,必须有一个格式良好的 XML 文档。
【讨论】:
谢谢,这就是我要找的。我玩过 set:district() 但我没有正确使用它。我将把它应用到我的生产系统中,让你知道它是如何进行的。 生产数据上有一个命名空间。我已更新问题以包含命名空间。 见:***.com/a/34762628/3016153 我终于明白为什么我不能让它工作了。我的一个输入文件在命名空间中,另一个不在,但它使用相同的标签。对人类来说,它们看起来是一样的。当我将命名空间添加到第二个文件时,我能够让生产系统正常工作。 您不需要修改您的输入。您可以简单地使用前缀来处理一个输入文件中的元素,使用无前缀名称来处理另一个文件中的元素。以上是关于XSLT - 在多个文件时选择唯一元素的主要内容,如果未能解决你的问题,请参考以下文章