如何基于XSLT参数创建要匹配的模板

如何基于XSLT参数创建要匹配的模板,xslt,xpath,Xslt,Xpath,我正在尝试创建一个标准的use XSLT,它将根据用户提供的XPATH表达式作为XSLT参数来执行给定的任务 也就是说,我需要这样的东西: <xsl:template match="$paramContainingXPATH"> <!-- perform the task on the node(s) in the given xpath --> </xsl:template> 例如,假设我有一些XML: <xml> <nodeA&

我正在尝试创建一个标准的use XSLT,它将根据用户提供的XPATH表达式作为XSLT参数来执行给定的任务

也就是说,我需要这样的东西:

<xsl:template match="$paramContainingXPATH">
  <!-- perform the task on the node(s) in the given xpath -->
</xsl:template>
例如,假设我有一些XML:

<xml>
  <nodeA>whatever</nodeA>
  <nodeB>whatever</nodeB>
  <nodeC>whatever</nodeC>
  <nodeD>whatever</nodeD>
  <nodeE>whatever</nodeE>
</xml>
XSLT只需要转换与提供的XPATH表达式匹配的一个或多个节点。因此,如果xslt参数为/xml/nodeC,它将处理nodeC。如果xslt参数是*[local name='nodeC'或local name='nodeE'],它将处理nodeC和nodeE

这绝对适用于任何XML消息。也就是说,XSLT不能直接了解XML的内容。因此,它可以是原始XML,也可以是SOAP信封

我猜我可能需要获取所有与xpath匹配的节点,然后在它们上循环调用命名模板,并对所有其他节点使用标准标识模板


所有的建议都被赏识了。

如果你真的需要XSLT 1或2的那个特性,那么我认为你应该考虑编写一个样式表,它使用XPath表达式获取那个字符串参数,然后简单地生成第二个样式表的代码,其中XPath表达式被用作匹配模式,而另一个需要模板。与标识模板一样,它们也是静态包含的。动态XPath评估只能在XSLT 3或早期版本中作为专有扩展机制使用。

< P>如果您确实需要XSLT 1或2的这个特性,那么我认为您应该考虑编写一个使用XPath表达式获取该字符串参数的样式表,然后简单地生成第二样式表的代码。其中XPath表达式用作匹配模式,其他所需模板(如标识模板)静态包含。动态XPath求值仅在XSLT 3.0或更早版本中作为专有扩展机制可用。

我将元素名称作为参数发送到XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
    <xsl:output method="xml"/>
    <xsl:param name="user"/>
    <xsl:template match="/">
        <xsl:call-template name="generic" />
    </xsl:template>
    <xsl:template name="generic">
        <count><xsl:value-of select="count(.//*[local-name()=$user])"/></count>
    </xsl:template>
</xsl:stylesheet>

我希望这能有所帮助

我将元素名作为参数发送到XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
    <xsl:output method="xml"/>
    <xsl:param name="user"/>
    <xsl:template match="/">
        <xsl:call-template name="generic" />
    </xsl:template>
    <xsl:template name="generic">
        <count><xsl:value-of select="count(.//*[local-name()=$user])"/></count>
    </xsl:template>
</xsl:stylesheet>

我希望这能有所帮助

不能使用参数匹配模板-但可以遍历树并将每个节点的路径与给定路径进行比较。下面是一个简单的例子:

XSLT1.0

应用于略为雄心勃勃的测试输入:

结果将是:

通过将累积路径作为递归模板的参数传递,可以提高效率,这样每个节点只需将自己的名称添加到链中

注:

给定的路径必须是绝对的

包括位置谓词和属性在内的谓词在此中未实现。他们可能会更努力一点

名称空间被忽略了,我不知道如何将XPath作为参数传递并包含名称空间

如果处理器支持evaluate扩展函数,则可以放弃计算文本路径,转而测试交叉点

编辑: 下面是一个使用EXSLT dyn:evaluate和set:intersection的示例:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
xmlns:set="http://exslt.org/sets"
extension-element-prefixes="dyn set">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:param name="path" select="'/world/America/USA/California'"/>
<xsl:variable name="path-set" select="dyn:evaluate($path)" />

<xsl:template match="/">
    <root>
        <xsl:apply-templates select="*"/>
    </root>
</xsl:template>

<xsl:template match="*">
    <xsl:if test="set:intersection(. , $path-set)">
        <xsl:call-template name="action"/>
    </xsl:if>
    <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template name="action">
    <return>
        <xsl:value-of select="." />
    </return>
</xsl:template>

</xsl:stylesheet>
请注意,这也适用于以下路径:

/世界/美国/美国/*[2]

//加州


文本比较方法无法适应的其他许多问题。

您无法使用参数匹配模板,但可以遍历树并将每个节点的路径与给定路径进行比较。下面是一个简单的例子:

XSLT1.0

应用于略为雄心勃勃的测试输入:

结果将是:

通过将累积路径作为递归模板的参数传递,可以提高效率,这样每个节点只需将自己的名称添加到链中

注:

给定的路径必须是绝对的

包括位置谓词和属性在内的谓词在此中未实现。他们可能会更努力一点

名称空间被忽略了,我不知道如何将XPath作为参数传递并包含名称空间

如果处理器支持evaluate扩展函数,则可以放弃计算文本路径,转而测试交叉点

编辑: 下面是一个使用EXSLT dyn:evaluate和set:intersection的示例:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
xmlns:set="http://exslt.org/sets"
extension-element-prefixes="dyn set">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:param name="path" select="'/world/America/USA/California'"/>
<xsl:variable name="path-set" select="dyn:evaluate($path)" />

<xsl:template match="/">
    <root>
        <xsl:apply-templates select="*"/>
    </root>
</xsl:template>

<xsl:template match="*">
    <xsl:if test="set:intersection(. , $path-set)">
        <xsl:call-template name="action"/>
    </xsl:if>
    <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template name="action">
    <return>
        <xsl:value-of select="." />
    </return>
</xsl:template>

</xsl:stylesheet>
请注意,这也适用于以下路径:

/世界/美国/美国/*[2]

//加州


还有许多其他的文本比较方法无法适应。

谢谢@MartinHonnen。我希望我能用EXSLT-dyn:evaluate完成它,但我不能把它放在模板匹配表达式中。我被XSLT1.0卡住了。您使用哪个XSLT1.0处理器?我首先要检查它是否有一个将参数作为XPath表达式处理的选项。一个示例会很有用,IMHO。示例在编辑到原始帖子中提供。谢谢@MartinHonnen。我希望我能用EXSLT-dyn:evaluate完成它,但我不能把它放在模板匹配表达式中。我被XSLT 1.0卡住了。XSLT 1.0处理哪种XSLT
你用什么?我会首先检查它是否有一个将参数作为XPath表达式处理的选项。一个例子会很有用,IMHO。在编辑到原始文章中提供的例子。不完全是我正在尝试的。我需要模板匹配表达式来匹配完整xpath表达式的模板匹配表达式。我当然可以基于xpath表达式抓取节点,但我需要对与用户提供的xpath表达式不匹配的所有节点执行标识转换,然后用模板转换与用户提供的xpath表达式匹配的所有节点。这与我的尝试不完全相同。我需要模板匹配表达式来匹配完整xpath表达式的模板匹配表达式。我当然可以基于xpath表达式获取节点,但我需要对所有与用户提供的xpath表达式不匹配的节点执行标识转换,然后使用模板转换所有与用户提供的xpath表达式匹配的节点。Nice。我也无法想象能够以这种方式处理名称空间。不过,我不确定,没有名称空间太危险了。我怀疑使用本地名称来构造路径是可行的。但是,我讨厌给定的路径必须是绝对路径,因为像//nodename这样的XPATH不起作用。是的,我有EXSLT评估。您将如何测试交叉点?@JMorgan如果您可以使用evaluate,那么许多无法使用此方法的东西将开始工作,包括//nodename,它是一个绝对路径。但是如果路径不是绝对的,那么样式表就不知道从哪个上下文来计算它。我相信唯一的解决办法是按照Martin Honnen的建议生成一个新的样式表。谢谢。它正在处理交叉点和动态评估.Nice。我也无法想象能够以这种方式处理名称空间。不过,我不确定,没有名称空间太危险了。我怀疑使用本地名称来构造路径是可行的。但是,我讨厌给定的路径必须是绝对路径,因为像//nodename这样的XPATH不起作用。是的,我有EXSLT评估。您将如何测试交叉点?@JMorgan如果您可以使用evaluate,那么许多无法使用此方法的东西将开始工作,包括//nodename,它是一个绝对路径。但是如果路径不是绝对的,那么样式表就不知道从哪个上下文来计算它。我相信唯一的解决办法是按照Martin Honnen的建议生成一个新的样式表。谢谢。它正在处理交叉点和动态评估。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
xmlns:set="http://exslt.org/sets"
extension-element-prefixes="dyn set">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:param name="path" select="'/world/America/USA/California'"/>
<xsl:variable name="path-set" select="dyn:evaluate($path)" />

<xsl:template match="/">
    <root>
        <xsl:apply-templates select="*"/>
    </root>
</xsl:template>

<xsl:template match="*">
    <xsl:if test="set:intersection(. , $path-set)">
        <xsl:call-template name="action"/>
    </xsl:if>
    <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template name="action">
    <return>
        <xsl:value-of select="." />
    </return>
</xsl:template>

</xsl:stylesheet>