XSLT 过滤元素 [英] XSLT filtering elements

查看:28
本文介绍了XSLT 过滤元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,假设输入 xml 具有以下结构:

For example, let's assume that input xml has following structure:

<root>
  <a>
    <aa>1</aa>
    <ab>2</ab>
    <ac>3</ac>
  </a>
  <b>
    <ba>4</ba>
    <bb>5</bb>
  <b>
  <c>
    <ca>
      <caa>6</caa>
      <cab>7</cab>
    </ca>
  </c>
</root>

给定一组 xpath 来过滤元素:

Given set of xpath to filter elements by:

/root/a/ab,
/root/a/ac,
/root/c/ca/cab

生成的 xml 应该是:

The resulting xml should be:

<root>
  <a>
    <ab>2</ab>
    <ac>3</ac>
  </a>
  <c>
    <ca>
      <cab>7</cab>
    </ca>
  </c>
</root>

XSLT 如何表达?

提前致谢

推荐答案

要在 XSLT 1.0(可能需要 EXSLT 的一些小帮助)或 2.0 中实现这一点,您可以首先将每个给定的路径分解为自身和祖先路径,因此那个:

To accomplish this in XSLT 1.0 (with possibly some small assistance by EXSLT) or 2.0, you could start by breaking each given path into itself and ancestor paths, so that:

/root/c/ca/cab

例如变成:

<path>/root/c/ca/cab</path>
<path>/root/c/ca</path>
<path>/root/c</path>
<path>/root</path>

通过命名递归模板应该不会太难完成.

This shouldn't be too difficult to accomplish by a named recursive template.

一旦你有了它,你就可以使用通过添加pass-thru"参数修改的身份转换,以便每个处理的元素可以计算到自身的路径,将其与给定的路径列表进行比较并确定它是否是否应该加入结果树.

Once you have that in place, you can use the identity transform modified by adding a "pass-thru" parameter so that each processed element can calculate the path to itself, compare it to the given list of paths and determine whether it should join the result tree or not.

在下面的样式表中,步骤 1 已被跳过,结果被当作给定使用.

In the following stylesheet, step 1 has been skipped and the result is being used as if given.

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="paths">
    <path>/root/a/ab</path>
    <path>/root/a</path>
    <path>/root</path>

    <path>/root/a/ac</path>
    <path>/root/a</path>
    <path>/root</path>

    <path>/root/c/ca/cab</path>
    <path>/root/c/ca</path>
    <path>/root/c</path>
    <path>/root</path>
</xsl:param>

<xsl:template match="@* | node()">
<xsl:param name="pathtrain" />
<xsl:variable name="path" select="concat($pathtrain, '/', name())" />
<xsl:if test="$path=exsl:node-set($paths)/path or not(self::*)">
    <xsl:copy>
         <xsl:apply-templates select="@* | node()">
            <xsl:with-param name="pathtrain" select="$path"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

应用于您的(更正)输入:

Applied to your (corrected) input of:

<root>
  <a>
    <aa>1</aa>
    <ab>2</ab>
    <ac>3</ac>
  </a>
  <b>
    <ba>4</ba>
    <bb>5</bb>
  </b>
  <c>
    <ca>
      <caa>6</caa>
      <cab>7</cab>
    </ca>
  </c>
</root>

得到如下结果:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <a>
    <ab>2</ab>
    <ac>3</ac>
  </a>
  <c>
    <ca>
      <cab>7</cab>
    </ca>
  </c>
</root>

<小时>

请注意,在使用上述基于字符串的测试时,重复的分支可能会产生误报.例如,当应用于以下输入时:

Note that duplicate branches may produce false positives when using a string-based test as above. For example, when applied to the following input:

<root>
  <a>
    <aa>1</aa>
    <ab>2</ab>
    <ac>3</ac>
  </a>
  <b>
    <ba>4</ba>
    <bb>5</bb>
  </b>
  <c>
    <ca>
      <caa>6</caa>
    </ca>
  </c>
  <c>
    <ca>
      <cab>7</cab>
    </ca>
  </c>
</root>

上面的样式表将产生:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <a>
    <ab>2</ab>
    <ac>3</ac>
  </a>
  <c>
    <ca/>
  </c>
  <c>
    <ca>
      <cab>7</cab>
    </ca>
  </c>
</root>

如果这是一个问题,我将发布另一个(更复杂的)XSLT 1.0 答案,通过测试唯一 ID 来消除该问题.

If this is a problem, I will post another (more complex) XSLT 1.0 answer that eliminates the issue by testing unique ids instead.

这篇关于XSLT 过滤元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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