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
,删除输入节点的第一个子节点。
答案 0 :(得分:1)
对于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>
答案 1 :(得分:0)
您可以使用:
<?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()<=1]"/>
</xsl:stylesheet>
如果你想要过滤第一个和第二个元素,它会将1改为2(它的工作方式与harpo的答案相同)。