繁体   English   中英

如何使用XSL删除XML节点的第一个子节点?

[英]How to remove the first child of an XML node with XSL?

Data.xls

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:variable name="Data" select="document('Data.xml')/*[1]"/>

<xsl:template match="/">
  <xsl:call-template name="remove-first-child">
    <xsl:with-param name="Node" select="$Data"/>
  </xsl:call-template>
</xsl:template>

<xsl:template name="remove-first-child">
  <xsl:param name="Node"/>
  <xsl:element name="{name($Node)}">
    <xsl:copy-of select="$Node/@* | $Node/*[position() > 1]"/>
  </xsl:element>
</xsl:template>

<!-- same as above, but for testing over 2 recursion levels -->
<xsl:template name="remove-first-child1">
  <xsl:param name="Node"/>
  <xsl:call-template name="remove-first-child">
    <xsl:with-param name="Node">
      <xsl:element name="{name($Node)}">
        <xsl:copy-of select="$Node/@* | $Node/*[position() > 1]"/>
      </xsl:element>
    </xsl:with-param>
  </xsl:call-template>
</xsl:template>

</xsl:stylesheet>

如何删除数据中的第一个孩子并产生可以再次传递给remove-first-child的输出?

调用第一个模板时,我得到:

$> msxsl Other.xml Data.xsl
<Alphabet>
  <B/>
  <C/>
  ...
</Alphabet>

当我更改为调用第二个模板时,我得到:

$> msxsl Other.xml Data.xsl
Error occured while executing stylesheet 'Data.xsl'.
Code:  0x80004005
Reference to variable or parameter 'Node' must evaluate to a node list.

理想的结果将是:

<Alphabet>
  <C/>
  ...
</Alphabet>

更新:我如何尝试应用建议的解决方案。

<xsl:template match="node()|@*" mode="remove-first-child">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*" mode="remove-first-child"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="node()[parent::*][not(preceding-sibling::*)]" mode="remove-first-child"/>

<xsl:template name="remove-first-child-a">
  <xsl:param name="Node"/>
  <xsl:apply-templates select="$Node" mode="remove-first-child"/>
</xsl:template>

<xsl:template name="remove-first-child-b">
  <xsl:param name="Node"/>
  <xsl:variable name="Temp">
    <xsl:apply-templates select="$Node" mode="remove-first-child"/>
  </xsl:variable>
  <xsl:apply-templates select="$Temp" mode="remove-first-child"/>  
</xsl:template>

<xsl:template match="/">
  <xsl:call-template name="remove-first-child-a">
  <!-- xsl:call-template name="remove-first-child-b" -->
    <xsl:with-param name="Node" select="$Data"/>
  </xsl:call-template>
</xsl:template>

但这也只会产生与上述相同的结果。 a

$> msxsl Other.xml Data.xsl
<Alphabet>
  <B/>
  <C/>
  ...
</Alphabet>

b

$> msxsl Other.xml Data.xsl
Error occured while executing stylesheet 'Data.xsl'.
Code:  0x80004005
Expression must evaluate to a node-set.
-->$Temp<--

所以我想关键是类型系统...

并且要注意:主要操作发生在Other.xml ,这不仅仅是一个虚拟调用。 一些数据是从Data.xml的,在与Other.xsl之前将要进行处理。 该处理仅包括删除依赖于某些条件(不是此问题的一部分)的第一个子对象,这些条件恰好是递归实现的,因为它是XSL。 并且在递归过程中,可能有必要删除相同和不同的遍历节点的多个第一个子级。

我想在XSL中表示的是投影node --> node ,删除输入节点的第一个子节点。

对于XSLT中的这种递归(即,遵循输入文档的结构),您要使用apply-templates而不是call-template 这避免了您遇到的问题(缺少节点集),因为该模板将仅应用于存在的节点。

以下转换设置了一个标准的身份模板,然后添加了对第一个子对象不产生任何影响的替代。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!-- Standard identity template -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>

    <!-- Skip first child -->
    <!-- the "parent" check is needed so that the root node is not skipped -->
    <xsl:template match="node()[parent::*][not(preceding-sibling::*)]" />

    <xsl:variable name="data-doc" select="document('Data.xml')"/>

    <xsl:template match="/">
        <xsl:apply-templates select="$data-doc/*" />
    </xsl:template>

</xsl:stylesheet>

应用于虚拟文档,其中外部文件Data.xml包含以下示例输入,

<A>
    <B1>
        <C1 />
        <C2 />
    </B1>
    <B2>
        <C1 />
        <C2 />
    </B2>
    <B3>
        <C1 />
        <C2>
            <D1 />
            <D2 />
        </C2>
        <C3>
            <D1 />
        </C3>
    </B3>
</A>

结果如下:

<?xml version="1.0" encoding="utf-8"?>
<A>
    <B2>
        <C2 />
    </B2>
    <B3>
        <C2>
            <D2 />
        </C2>
        <C3>
        </C3>
    </B3>
</A>

您可以使用 :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/*//*[position()&lt;=1]"/>     
</xsl:stylesheet>

如果要同时过滤第一个和第二个元素,则将“ 1”乘“ 2”(按harpo的答案中的说明工作)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM