XSL根据条件删除元素

时间:2013-10-12 12:24:18

标签: xml xslt

我有一个大致如下的XML文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Multiple xmlns:ns2="someNs2" xmlns="someGenericNs" xmlns:ns4="someNs4" xmlns:ns3="someNs3">
  <Single>
    <Id>60000</Id>
    <Type>Activate</Type>
    <Payload>
      <ns3:Activation>
        <ns3:Parent>
          <ns3:TypeId>113</ns3:TypeId>
          <ns3:TypeName>TestApplication</ns3:TypeName>
        </ns3:Parent>
        <ns3:Children>
          <ns3:Child>
            <ns3:Key>someKey</ns3:Key>
            <ns3:ChildTypeName>BadAppType1</ns3:ChildTypeName>
          </ns3:Child>
          <ns3:Child>
            <ns3:Key>someOtherKey</ns3:Key>
            <ns3:ChildTypeName>GoodAppType1</ns3:ChildTypeName>
          </ns3:Child>
        </ns3:Children>
      </ns3:Activation>
    </Payload>
  </Single>
</Multiple>

我需要做的是将其转换为更简单的形式,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<MyNewRootNode xmlns="MyNewNamespace">
    <Activation>
        <ApplicationType>TestApplication</ApplicationType>
        <ValidChildTypeName>GoodAppType1</ValidChildTypeName>
        <ValidChildKey>someOtherKey</ValidChildKey>
    </Activation>
</MyNewRootNode>

初始XML可以包含多个子节点,其中只有一个具有有效的“CildTypeName”节点。我的问题是,如果XML确实包含多个子节点,那么我的XSLT将只抓取第一个并将其转换为新格式,即使它包含无效的“ChildTypeName”。

总结一下:我需要将XML转换为更简单的形式。要创建这个更简单的表单,我需要筛选所有“子”节点并找到包含有效“ChildTypeName”的节点,并将其“Key”和“ChildTypeName”的值复制到新节点XML。

我还有一个有效“ChildTypeNames”的预定义列表。它包含大约3个名字,不会很快改变。

这是我到目前为止所学到的XSLT:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="MyNewNamespace" xmlns:ns3="someNs3" exclude-result-prefixes="ns3">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:variable name="activationNode">
        <xsl:text>Activation</xsl:text>
    </xsl:variable>
    <xsl:variable name="new-root-node">
        <xsl:text>MyNewRootNode</xsl:text>
    </xsl:variable>

    <xsl:template match="/*">
        <xsl:element name="{$new-root-node}">
            <xsl:element name="{$activationNode}">
                <xsl:call-template name="TemplateOne"/>
            </xsl:element>
        </xsl:element>
    </xsl:template>


    <xsl:template name="TemplateOne">
        <xsl:element name="ApplicationType">
            <xsl:value-of select="//ns3:Activation/ns3:Parent/ns3:TypeName"/>
        </xsl:element>
        <xsl:element name="ValidChildTypeName">
            <xsl:value-of select="//ns3:Activation/ns3:Children/ns3:Child/ns3:ChildTypeName"/>
        </xsl:element>
        <xsl:element name="ValidChildKey">
            <xsl:value-of select="//ns3:Activation/ns3:Children/ns3:Child/ns3:Key"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

但是这将抓住它找到的第一个子节点,在这种情况下是“BadAppType1”。

更新:在此方面取得了一些进展。将XSLT的最后一部分更改为:

<xsl:for-each select="//ns3:Activation/ns3:Children/ns3:Child">
            <xsl:if test="ns3:ChildTypeName[text()='GoodAppType1']">
                <xsl:element name="ValidChildTypeName">
                    <xsl:value-of select="ns3:ChildTypeName"/>
                </xsl:element>
                <xsl:element name="ValidChildKey">
                    <xsl:value-of select="ns3:Key"/>
                </xsl:element>
            </xsl:if>
        </xsl:for-each>

据我所知,我只需要一种方法来检查多个可能的有效值,它应该是正确的。

1 个答案:

答案 0 :(得分:1)

如果您尝试选择激活元素,其 Child 元素的 ChildTypeName 为&#34; GoodAppType1&#34;那么也许你可以使用模板匹配来选择它存在的元素。

<xsl:apply-templates 
     select="//ns3:Activation[ns3:Children/ns3:Child/ns3:ChildTypeName='GoodAppType1']" />

然后,在与此匹配的模板中,您可以轻松输出 ApplicationType

<ApplicationType><xsl:value-of select="ns3:Parent/ns3:TypeName" /></ApplicationType>

然后,选择包含 ChildTypeName

Child 元素
<xsl:apply-templates select="ns3:Children/ns3:Child[ns3:ChildTypeName='GoodAppType1']" />

在匹配儿童的模板中,您同样可以输出 ChildTypeName

尝试以下XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="MyNewNamespace" xmlns:ns3="someNs3" exclude-result-prefixes="ns3">
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

   <xsl:variable name="activationNode">
      <xsl:text>Activation</xsl:text>
   </xsl:variable>

   <xsl:variable name="new-root-node">
      <xsl:text>MyNewRootNode</xsl:text>
   </xsl:variable>

   <xsl:template match="/">
      <xsl:element name="{$new-root-node}">
         <xsl:apply-templates select="//ns3:Activation[ns3:Children/ns3:Child/ns3:ChildTypeName='GoodAppType1']"/>
      </xsl:element>
   </xsl:template>

   <xsl:template match="ns3:Activation">
      <xsl:element name="{$activationNode}">
         <ApplicationType>
            <xsl:value-of select="ns3:Parent/ns3:TypeName"/>
         </ApplicationType>
         <xsl:apply-templates select="ns3:Children/ns3:Child[ns3:ChildTypeName='GoodAppType1']"/>
      </xsl:element>
   </xsl:template>

   <xsl:template match="ns3:Child">
      <ValidChildTypeName>
         <xsl:value-of select="ns3:ChildTypeName"/>
      </ValidChildTypeName>
      <ValidChildKey>
         <xsl:value-of select="ns3:Key"/>
      </ValidChildKey>
   </xsl:template>
</xsl:stylesheet>

针对输入XML运行时,输出以下内容

<MyNewRootNode xmlns="MyNewNamespace">
  <Activation>
    <ApplicationType>TestApplication</ApplicationType>
    <ValidChildTypeName>GoodAppType1</ValidChildTypeName>
    <ValidChildKey>someOtherKey</ValidChildKey>
  </Activation>
</MyNewRootNode>