删除与特定节点关联的所有子元素,并替换为单个子元素

时间:2014-08-27 16:22:52

标签: xml xslt xslt-2.0

我是XSLT的新手,但是我为工作做了很多XML修改,所以我正在努力学习。我以下列格式输入XML(上面和下面有XML):

<Parent Value="x">
<!---->Unlimited number of child elements could exist with any value from 0-1
    <Child Value="0.1"/>
    <Child Value="1"/>
    <Child Value="0.30"/>
    ...
</Parent>

我需要以下列格式的父/子节点输出XML

<Parent Value="x">
    <Child Value="0.3"/>
</Parent>

只有一个子元素且其值恒定为0.3。

我的当前XSLT 类似:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"     xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
<xsl:output method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="yes" indent="yes"/>

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

<xsl:template match="Parent">
    <Parent>
        <xsl:apply-templates select="@*|*"/>
        <Child Value="0.3"/>
    </Parent>
</xsl:template>

<xsl:template match="Child[@Value!=0.3]"/>

我试图在所有文件中创建所需的子元素(如果它不存在的话)

<Child Value="0.3"/>

然后仅在其值= 0.3时输出子元素。但是,这有时会导致子节点的重复,我觉得我可能不会以正确的方式接近它。此外,xmlns:xs标题出现在Parent元素之后,而不是在输出文档的顶部。任何指导将不胜感激!

当前输出示例:

<Parent Value="x" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
    <Child Value="0.30" />
    <Child Value="0.3" />
</Parent>

2 个答案:

答案 0 :(得分:2)

只有两件事需要修改:

1 在此处使用单引号:

<xsl:template match="Child[@Value!='0.3']"/>

如果您没有,则该值将被解释为数字,否则将被解释为字符串。为什么这很重要?因为如果表达式的右侧是数字,则属性值也会转换为数字 - 而0.30.30最终会相同。最终导致输出多个Child元素。

2 使用Child有意插入xsl:if元素。显而易见,取决于此特定元素是否已存在于输入中。然后,您不会在输出中获得两个Child元素。

注意:Parent中不是属性或元素节点(即processing-instruction()comment())的任何子节点都会在样式表中被忽略。这是因为您只将模板应用于@*|*,而不是@*|node()

<强>样式表

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"     xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
<xsl:output method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="yes" indent="yes"/>

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

<xsl:template match="Parent">
    <Parent>
        <xsl:apply-templates select="@*|*"/>
        <xsl:if test="not(Child[@Value = '0.3'])">
            <Child Value="0.3"/>
        </xsl:if>
    </Parent>
</xsl:template>

<xsl:template match="Child[@Value!='0.3']"/>

</xsl:stylesheet>

XML输入

<?xml version="1.0" encoding="UTF-8"?>
<Parent Value="x">
    <Child Value="0.30"/>
    <Child Value="1"/>
    <Child Value="0.4"/>
    <Child Value="0.3">The right one</Child>
</Parent>

XML输出

<Parent xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:fn="http://www.w3.org/2005/xpath-functions"
        xmlns:xdt="http://www.w3.org/2005/xpath-datatypes"
        Value="x">
   <Child Value="0.3">The right one</Child>
</Parent>

目前,输出XML中有未使用的命名空间。您可以通过将exclude-result-prefixes="#all"添加到xsl:stylesheet来阻止它们出现在输出中。如果这样做,那么输出将简化为

<Parent Value="x">
   <Child Value="0.3">The right one</Child>
</Parent>

答案 1 :(得分:0)

您使用基于身份的转换进入了正确的轨道,但您可能需要在父级的模板中创建单个子级:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="yes" indent="yes"/>

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

<xsl:template match="Child"/>

<xsl:template match="Parent">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <Child Value="0.3"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>