如何创建模板以根据 XSLT 参数进行匹配 [英] How to create template to match based upon an XSLT parameter

查看:25
本文介绍了如何创建模板以根据 XSLT 参数进行匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create a standard-use XSLT that will perform a given task based upon a user-provided XPATH expression as an XSLT parameter.

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

That is, I need something like this:

<xsl:template match="$paramContainingXPATH">
  <!-- perform the task on the node(s) in the given xpath -->
</xsl:template>

例如,假设我有一些 XML:

For example, suppose I have some 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' or local-name() = 'nodeE']",则处理 nodeC 和 nodeE.

The XSLT needs to transform just a node or nodes matching a provided XPATH expression. So, if the xslt parameter is "/xml/nodeC", it processes nodeC. If the xslt parameter is "*[local-name() = 'nodeC' or local-name() = 'nodeE']", it processes nodeC and nodeE.

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

This should work for absolutely any XML message. That is, the XSLT cannot have any direct knowledge of the content of the XML. So, it could be a raw XML, or a SOAP Envelope.

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

I was guessing I might need to grab all the nodes matching the xpath, and then looping over them calling a named template, and using the standard identity template for all other nodes.

感谢所有建议.

推荐答案

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

You cannot match a template using a parameter - but you can traverse the tree and compare the path of each node with the given path. Here's a simple example:

XSLT 1.0

<?xml version="1.0" encoding="UTF-8"?>
<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="path" select="'/world/America/USA/California'"/>

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

<xsl:template match="*">
    <xsl:variable name="path-to-me">
        <xsl:for-each select="ancestor-or-self::node()">
            <xsl:value-of select="name()" />
            <xsl:if test="position()!=last()">
                <xsl:text>/</xsl:text>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable> 
    <xsl:if test="$path=$path-to-me">
        <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>

应用于稍微更雄心勃勃的测试输入:

Applied to a slightly more ambitious test input of:

<world>
    <Europe>
        <Germany>1</Germany>
        <France>2</France>
        <Italy>3</Italy>
    </Europe>
    <America>
        <USA>
            <NewYork>4</NewYork>
            <California>5</California>
        </USA>
        <Canada>6</Canada>
    </America>
</world>

结果:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <return>5</return>
</root>

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

This could be made more efficient by passing the accumulated path as a parameter of the recursive template, so that each node needs only to add its own name to the chain.

注意:

  1. 给定的路径必须是绝对路径;

  1. The given path must be absolute;

谓词(包括位置谓词)和属性未在此实现.他们可能会多一些努力;

Predicates (including positional predicates) and attributes are not implemented in this. They probably could be, with a bit more effort;

命名空间被忽略(我不知道您如何将 XPath 作为参数传递并包含命名空间).

Namespaces are ignored (I don't see how you could pass an XPath as a parameter and include namespaces anyway).

如果您的处理器支持evaluate() 扩展函数,您可以放弃计算的文本路径并改为测试交集.

If your processor supports an evaluate() extension function, you could forgo the calculated text path and test for intersection instead.

这是一个使用 EXSLT dyn:evaluate() 和 set:intersection() 的例子:

Here's an example using EXSLT dyn:evaluate() and 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>

请注意,这也适用于以下路径:

Note that this will also work with with paths like:

/world/America/USA/*[2]

//加利福尼亚

以及文本比较方法无法容纳的许多其他内容.

and many others that the text comparison method could not accommodate.

这篇关于如何创建模板以根据 XSLT 参数进行匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆