XSLT选择性副本

时间:2013-12-04 01:19:06

标签: xml xslt

我正在首次涉足XML转换,我希望使用XSLT来执行XML - > XML转换,我尝试了几种方法(不成功)根据特定属性过滤节点......

源xml文件,如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
    <resource name="zoo">   
     <resource name="foo">
          <customResource name="bar">
           <value name="Zanibar"/>
           <value name="Echo"/>
           <value name="Blah"/>
          </customResource>
        </resource>

       <resource name="otherfoo">
          <customResource name="otherbar">
           <value name="crowbar"/>
           <value name="motar"/>
           <value name="brick"/>
          </customResource>
        </resource>

     </resource>

我的xsl看起来像这样:

<?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" omit-xml-declaration="yes" indent="yes"/>

    <!-- this template sets match for all nodes at root level and iterates and makes a copy subject to templates
        if no other templates are defined this will make an exact copy -->
    <xsl:template match="*">
        <xsl:copy>
            <xsl:for-each select="@*">
                <xsl:copy>
                    <xsl:apply-templates/>
                </xsl:copy>
            </xsl:for-each>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template> 

    <!-- find foo/bar and rebuild with only desired values -->
    <xsl:template match="//foo/bar/">
        <xsl:copy-of select="//value[@name='Echo']" />
    </xsl:template>
    </xsl:template>
</xsl:stylesheet>

我希望得到一个如下所示的过滤结果:

<?xml version="1.0" encoding="UTF-8" ?>
    <resource name="zoo">   
     <resource name="foo">
          <customResource name="bar">
           <value name="Echo"/>
          </customResource>
        </resource>

       <resource name="otherfoo">
          <customResource name="otherbar">
           <value name="crowbar"/>
           <value name="motar"/>
           <value name="brick"/>
          </customResource>
        </resource>
     </resource>

只有我最终得到原始xml的完整副本,而不是我的过滤版本。

提前感谢任何建议! EB

此模板中的结果与之前的尝试类似;即,它执行包容性过滤,但删除父节点上的属性

<resource name="foo">
          <customResource> <!-- should still have name="bar" -->
           <value name="Echo"/>
          </customResource>
        </resource>

最新的结果非常接近我一直在寻找的转换,在一种情况下,格式化已被删除,但在另一种情况下没有...(我在linux上使用xsltproc)

<resource name="foo">
          <customResource name="bar"><value name="Echo"/></customResource>
        </resource>

但是这部分并不像处理具有相同名称属性的重复自定义资源那样重要,我很抱歉我之前应该提到过。 e.g。

<?xml version="1.0" encoding="UTF-8" ?>
    <resource name="zoo">  
     <resource name="nested"> 
     <resource name="foo">
          <customResource name="bar">
           <value name="Zanibar"/>
           <value name="Echo"/>
           <value name="Blah"/>
          </customResource>
        </resource>
       </resource>
       <resource name="foo">
          <customResource name="otherbar">
           <value name="crowbar"/>
           <value name="motar"/>
           <value name="brick"/>
          </customResource>
        </resource>
     </resource>

“foo”的模板过滤清空了重复资源下的customResources ... 再次道歉,当我翻译成foobar土地时,我蠢蠢欲动:-) 我能够过滤各种“foo”并在customResources“bar”,“otherbar”等之间切换......改为使用copy而不是                                           

1 个答案:

答案 0 :(得分:3)

这是一种看待它的方法:

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

<xsl:strip-space elements="*"/>

<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

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

<!-- exception -->
<xsl:template match="value[@name!='Echo']"/>

</xsl:stylesheet>

另见:
http://en.wikipedia.org/wiki/Identity_transform


编辑

这是一种不同的方法,允许您选择要包含在每个值中的值 customResource:

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

<xsl:strip-space elements="*"/>
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

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

<xsl:template match="customResource">
    <xsl:choose>
        <xsl:when test="@name='bar'">
            <xsl:copy>  
                <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="value[@name='Echo']"/>
            </xsl:copy>
        </xsl:when>

        <xsl:when test="@name='otherbar'">
            <xsl:copy>  
                <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="value[@name='crowbar']"/>
            </xsl:copy>
        </xsl:when>
        <!-- continue for other customResources  -->
    </xsl:choose>   
</xsl:template>

</xsl:stylesheet>

编辑2

如果您愿意,可以通过其父级名称选择customResource,如下所示:

<xsl:when test="parent::resource/@name='foo'">

如果那不够具体(即如果父资源可以有多个customResource),那么测试两个名称

无论如何,我相信你已经足够自己完成这项任务了。