我想在最左边的叶子中添加一个具有给定名称的节点。 例如,
<root>
<aaa name="a">
<aaa name="x"/>
</aaa>
<aaa name="b">
<aaa name="y">
<aaa name="z"/>
</aaa>
</aaa>
<aaa name="c">
<aaa name="z"/>
</aaa>
</root>
给定name =“z”并且给定新节点为<aaa name="w">
。
新树应该是以下形式:
<root>
<aaa name="a">
<aaa name="x"/>
</aaa>
<aaa name="b">
<aaa name="y">
<aaa name="z">
<aaa name="w"/>
</aaa>
</aaa>
</aaa>
<aaa name="c">
<aaa name="z"/>
</aaa>
</root>
答案 0 :(得分:2)
如果最左边是指具有最大深度的'z'节点,则可以先定义一个变量来计算出最左边的'z'的深度,然后在匹配时添加'w'节点这样一个深度的节点
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Work out depth of left most 'z' node -->
<xsl:variable name="LeftMost">
<xsl:for-each select="//*[@name='z']">
<xsl:sort select="count(ancestor::*)" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="count(ancestor::*)"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:if test="@name='z' and count(ancestor::*) = $LeftMost">
<aaa name="w"/>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
使用这个,如果你有两个'z'节点在同一深度,你最终会得到一个'w'节点。
另一种方法是使用generate-id()来获取最大深度的第一个'z'的ID,然后在匹配具有相同id的节点时添加'w'。然后,这只会在它找到的最大深度的第一个'z'节点上添加一个'w'节点。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="LeftMost">
<xsl:for-each select="//*[@name='z']">
<xsl:sort select="count(ancestor::*)" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="generate-id()"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:if test="@name='z' and generate-id() = $LeftMost">
<aaa name="w"/>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:2)
@Tim C's variable based approach的变体会涉及<xsl:key>
和前一轴,如下所示:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:key
name="kCountPreceding" match="aaa[@name='z']"
use="count(preceding::aaa[@name='z'])"
/>
<xsl:variable name="vLeftMostId" select="
generate-id(key('kCountPreceding', 0))"
/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
<xsl:if test="generate-id() = $vLeftMostId">
<aaa name="w" />
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这种方法的缺点是,匹配表达式中不允许任何变量。这意味着这不能动态化,密钥的match="aaa[@name='z']"
必须是硬编码的。
答案 2 :(得分:0)
你可以从这样的事情开始:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:if test="@name='z'">
<aaa name="w"/>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 3 :(得分: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:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="*[@name='z' and not(preceding::*[@name='z'])]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<aaa name="w" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
顺便说一下,最左边的叶子是文件顺序中的第一片叶子,不是吗?
<xsl:for-each select="/descendant::*[@name='z' and not(*)][1]">
...
<aaa name="w" />
...
</xsl:for-each>
答案 4 :(得分:0)
最左边的叶子是第一片叶子 文件顺序,不是吗?
是的,第一片叶子,名字为