排除子节点元素的 XPath 选择

XPath selection excluding element from a child node

我需要 select 所有 <next> 节点,但从每个节点中排除 <element4> 并在其位置添加一个新元素(这将是一个替换)。我正在与 php.

合作
<root>
<next>
  <node>
    <element1>text</element1>
    <element2>text</element1>
    <element3>text</element1>
    <element4>text</element1>
  </node>   
  <node>
    <element1>text</element1>
    <element2>text</element1>
    <element3>text</element1>
    <element4>text</element1>
  </node>   
</next> 
</root>

所以它应该是这样的:

<next>
  <node>
    <element1>text</element1>
    <element2>text</element1>
    <element3>text</element1>
    <new>text</new>
  </node>   
  <node>
    <element1>text</element1>
    <element2>text</element1>
    <element3>text</element1>
    <new><int xmlns="foo.bar">0</int></new>
  </node>   
</next> 

有什么建议吗?谢谢!

XPath 是一种选择语言:它从输入序列中选择节点或原子项,它是对 XML 或分层数据进行选择的首选语言,因为 SQL 是 (通常)关系数据库的首选语言。

因此,您可以从选择中排除 元素,但不能更新更改 原始序列。可以进行有限的转换(即,将字符串转换为整数),但这会更改所选内容,不会更改源。虽然 XPath(即 2.0 版及更高版本)可以 "create" 即时原子值,但它不能创建新元素。

这是可能的,并且将 return XPath 2.0 中的数值:

/next/node/number(.)

但这是不可能的:

/next/node/(if (element4) then create-element(.) else .)

但是,在 XSLT 2.0 及更高版本中,您可以创建一个创建元素的函数。上面说了XPathselects,如果你想改变文档,你可以使用XSLT创建一个新文档(T代表Transformation ).

类似下面的内容(部分 XSLT 2.0,您需要添加 headers):

<xsl:function name="f:create">
    <xsl:param name="node" />
    <xsl:param name="name" />
    <xsl:choose>
        <xsl:when test="name($node) = $name">
            <xsl:element name="{if(number($node)) then 'int' else 'new'}">
                <xsl:value-of select="$node" />
            </xsl:element>
        </xsl:when>
        <xsl:otherwise><xsl:copy-of select="$node" /></xsl:otherwise>
    </xsl:choose>
</xsl:function>

<xsl:template match="node">
    <!-- now XPath, with help of XSLT function, can conditionally create nodes -->
    <xsl:copy-of select="child::*/create(., 'element4')" />
</xsl:template>

<!-- boilerplate code, typically used to recursively copy non-matched nodes -->
<xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
</xsl:template>

请注意,虽然这显示了如何使用 XPath 和 XSLT 函数创建不同的元素,但它并没有改变源,而是改变了输出。此外,这不是推荐的做法,因为在 XSLT 中,只需执行以下操作即可更轻松地完成相同的模式:

<!-- the more specific match -->
<xsl:template match="element4[number(.)]">
    <new>
        <int  xmlns="foo.bar">
            <xsl:value-of select="number(.)" />
        </int>
    </new>
<xsl:template>

<!-- XSLT will automatically fallback to this one if the former fails -->
<xsl:template match="element4">
    <new><xsl:copy-of select="node()" /></new>
</xsl:template>

<!-- or this one, if both the former fail -->
<xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
</xsl:template>