2

我有一个大致如下所示的 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 转换为更简单的形式。要创建这个更简单的表单,我需要过滤所有“Child”节点并找到包含有效“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>

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

4

1 回答 1

1

如果您尝试选择具有ChildTypeName为“GoodAppType1”的Child元素的Activation元素,那么也许您可以使用模板匹配来选择存在的此类元素。

<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的子元素

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

在匹配Child的模板中,您同样可以输出KeyChildTypeName

尝试以下 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>
于 2013-10-12T18:05:48.163 回答