XSLT - 在多个文件时选择唯一元素
XSLT - Selecting unique elements when multiple files
我不知道如何通过 xsltproc 使用两个文件来完成这项工作。 cooking.xml 使用 document() 打开,menu.xml 在命令行中传入。我可以 select 没有问题的食谱,我想不通的是如何获得独特的配料清单。当我在我的配料列表中使用前面的兄弟函数时,它的行为类似于 {[shell, beef, lettuce, tomato, cheese], [eggs, cheese]}。为什么像“cooking/recipe[@name = $menu]/ingredients”这样的 select 会创建一个我不能在其上使用 preceding-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>
Why does a select like "cooking/recipe[@name = $menu]/ingredients" create a disjoint set that I can't use preceding-sibling on?
因为 preceding-sibling
轴是在输入树的上下文中计算的,而不是在 selection 的上下文中计算的。如果您 将 您的 selection 复制到一个变量,情况会有所不同。
无论哪种方式,使用 preceding-sibling
轴都不是 select 唯一值的好方法。如果您使用 xsltproc
(即 libxslt
),那么您可以这样做:
XSLT 1.0 + EXSLT set:distinct-值()
<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 文档。
我不知道如何通过 xsltproc 使用两个文件来完成这项工作。 cooking.xml 使用 document() 打开,menu.xml 在命令行中传入。我可以 select 没有问题的食谱,我想不通的是如何获得独特的配料清单。当我在我的配料列表中使用前面的兄弟函数时,它的行为类似于 {[shell, beef, lettuce, tomato, cheese], [eggs, cheese]}。为什么像“cooking/recipe[@name = $menu]/ingredients”这样的 select 会创建一个我不能在其上使用 preceding-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>
Why does a select like "cooking/recipe[@name = $menu]/ingredients" create a disjoint set that I can't use preceding-sibling on?
因为 preceding-sibling
轴是在输入树的上下文中计算的,而不是在 selection 的上下文中计算的。如果您 将 您的 selection 复制到一个变量,情况会有所不同。
无论哪种方式,使用 preceding-sibling
轴都不是 select 唯一值的好方法。如果您使用 xsltproc
(即 libxslt
),那么您可以这样做:
XSLT 1.0 + EXSLT set:distinct-值()
<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 文档。