如何使用XSLT基于节点属性拆分XML文件?

时间:2012-05-06 08:04:56

标签: xml xslt split

如果我有这个输入文件:

<root> 
    <node id="N1">
        <fruit id="small_fruit">
            <orange id="1" action="create">
                <attribute>
                    <color>yellow</color>
                </attribute>
            </orange>
        </fruit>

        <fruit id="large_fruit" action="create">
            <melon id="1" action="destroy">
                <attribute>
                    <color>green</color>
                </attribute>
            </melon>
        </fruit>            
    </node>

    <node id="N2">
        <dog id="small_dog">    
            <poodle id="1" action="create">
                <attribute>
                    <color>Yellow</color>    
                </attribute>
            </poodle>       

            <poodle id="1" action="change">
                <attribute>
                    <color>Brown</color>        
                </attribute>
            </poodle>

            <terrier id="2" action="destroy">
                <attribute>
                    <color>Blue</color>    
                </attribute>
            </terrier>
        </dog>                          
    </node>
</root>

我需要分成两个文件: output1:node_destroy.xml

<root> 
    <node id="N1">          
        <fruit id="large_fruit" action="create">
            <melon id="1" action="destroy">
                <attribute>
                    <color>green</color>
                </attribute>
            </melon>
        </fruit>            
    </node>

    <node id="N2">
        <dog id="small_dog">                
            <terrier id="2" action="destroy">
                <attribute>
                    <color>Blue</color>    
                </attribute>
            </terrier>
        </dog>                          
    </node>
</root>

output2:node_other_than_destroy.xml

<root> 
    <node id="N1">
        <fruit id="small_fruit">
            <orange id="1" action="create">
                <attribute>
                    <color>yellow</color>
                </attribute>
            </orange>
        </fruit>                  
    </node>

    <node id="N2">
        <dog id="small_dog">    
            <poodle id="1" action="create">
                <attribute>
                    <color>Yellow</color>    
                </attribute>
            </poodle>       

            <poodle id="1" action="change">
                <attribute>
                    <color>Brown</color>        
                </attribute>
            </poodle>
        </dog>                          
    </node>
</root>

基本上我需要将具有action ='destroy'的节点移除到一个文件,将其他节点移除到另一个文件中。 (选中的行动节点是甜瓜,贵宾犬,小猎犬不是他们的父母,即水果和狗

请帮我转换文件。非常感谢。

的问候, 约翰

2 个答案:

答案 0 :(得分:2)

您使用哪种XSLT处理器?如果这是一个XSLT 2.0处理器,如Saxon 9或AltovaXML或XmlPrime,那么您可以使用the xsl:result-document instruction。使用XSLT 1.0处理器,您需要检查处理器是否支持扩展指令以创建多个结果文档。 因此,请告诉我们您使用的处理器,然后我们可以为您的输入样本和所需的输出样本建议具体的代码示例。

[编辑] 我准备了一个XSLT 2.0示例:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
  version="2.0">

  <xsl:param name="action" as="xs:string" select="'destroy'"/>

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

  <xsl:template match="/">
    <xsl:result-document href="node_{$action}.xml">
      <xsl:apply-templates/>
    </xsl:result-document>
    <xsl:result-document href="node_other_than_{$action}.xml">
      <xsl:apply-templates mode="other"/>
    </xsl:result-document>
  </xsl:template>

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

  <xsl:template match="/*/*[*/*[@action = $action]] 
                       | /*/*/*[*[@action = $action]]">
    <xsl:next-match/>
  </xsl:template>

  <xsl:template match="/*/*[not(*/*[@action = $action])] 
                       | /*/*/*[not(*[@action = $action])]
                       | /*/*/*/*[not(@action = $action)]"/>

  <xsl:template match="/*/*[*/*[not(@action = $action)]] 
                       | /*/*/*[*[not(@action = $action)]]" mode="other">
    <xsl:next-match/>
  </xsl:template>

  <xsl:template match="/*/*[not(*/*[not(@action = $action)])] 
                       | /*/*/*[not(*[not(@action = $action)])]
                       | /*/*/*/*[@action = $action]" mode="other"/>


</xsl:stylesheet>

答案 1 :(得分:2)

在XSLT 1.0中,无法通过一次转换执行创建多个输出

以下是两个单独的XSLT 1.0转换

第一个只生成action="destroy的结果:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="node[not(*/*/@action = 'destroy')]"/>
 <xsl:template match="node/*[not(*/@action = 'destroy')]"/>

 <xsl:template match="node/*/*[not(@action = 'destroy')]"/>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<root>
    <node id="N1">
        <fruit id="small_fruit">
            <orange id="1" action="create">
                <attribute>
                    <color>yellow</color>
                </attribute>
            </orange>
        </fruit>

        <fruit id="large_fruit" action="create">
            <melon id="1" action="destroy">
                <attribute>
                    <color>green</color>
                </attribute>
            </melon>
        </fruit>
    </node>

    <node id="N2">
        <dog id="small_dog">
            <poodle id="1" action="create">
                <attribute>
                    <color>Yellow</color>
                </attribute>
            </poodle>

            <poodle id="1" action="change">
                <attribute>
                    <color>Brown</color>
                </attribute>
            </poodle>

            <terrier id="2" action="destroy">
                <attribute>
                    <color>Blue</color>
                </attribute>
            </terrier>
        </dog>
    </node>
</root>

产生了想要的正确结果:

<root>
   <node id="N1">
      <fruit id="large_fruit" action="create">
         <melon id="1" action="destroy">
            <attribute>
               <color>green</color>
            </attribute>
         </melon>
      </fruit>
   </node>
   <node id="N2">
      <dog id="small_dog">
         <terrier id="2" action="destroy">
            <attribute>
               <color>Blue</color>
            </attribute>
         </terrier>
      </dog>
   </node>
</root>

第二个转型产品所有“非破坏”内容:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="node[not(*/*/@action[not(. = 'destroy')])]"/>
 <xsl:template match="node/*[not(*/@action[not(. = 'destroy')])]"/>

 <xsl:template match="node/*/*[@action = 'destroy']"/>
</xsl:stylesheet>

将此转换应用于同一XML文档(上图)时,会生成所需结果:

<root>
   <node id="N1">
      <fruit id="small_fruit">
         <orange id="1" action="create">
            <attribute>
               <color>yellow</color>
            </attribute>
         </orange>
      </fruit>
   </node>
   <node id="N2">
      <dog id="small_dog">
         <poodle id="1" action="create">
            <attribute>
               <color>Yellow</color>
            </attribute>
         </poodle>
         <poodle id="1" action="change">
            <attribute>
               <color>Brown</color>
            </attribute>
         </poodle>
      </dog>
   </node>
</root>

<强> II。 XSLT 2.0解决方案 - 在同一转换中创建两个输出文件:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

 <xsl:template match="/">
   <xsl:variable name="vResultDestroyed">
     <xsl:apply-templates mode="destroyed"/>
   </xsl:variable>
   <xsl:variable name="vResultNonDestroyed">
     <xsl:apply-templates mode="non-destroyed"/>
   </xsl:variable>

   <xsl:for-each select="1 to 2">
     <xsl:result-document
        href="file:///c:temp/delete/{'non-'[position()=current()]}destroyed.xml">
      <xsl:copy-of select=
       "($vResultNonDestroyed, $vResultDestroyed)[position() = current()]"/>
     </xsl:result-document>
   </xsl:for-each>
 </xsl:template>

 <xsl:template mode="destroyed" match="node[not(*/*/@action = 'destroy')]"/>
 <xsl:template mode="destroyed" match="node/*[not(*/@action = 'destroy')]"/>
 <xsl:template mode="destroyed" match="node/*/*[not(@action = 'destroy')]"/>

 <xsl:template mode="non-destroyed"  match="node[not(*/*/@action[not(. = 'destroy')])]"/>
 <xsl:template mode="non-destroyed"  match="node/*[not(*/@action[not(. = 'destroy')])]"/>
 <xsl:template mode="non-destroyed"  match="node/*/*[@action = 'destroy']"/>
</xsl:stylesheet>

使用Saxon 9.1.07运行此转换时,正确的输出将写入文件

C:\Program Files\Java\jre6\bin\temp\delete\destroyed.xml

C:\Program Files\Java\jre6\bin\temp\delete\non-destroyed.xml