将包含子节点列表的xml转换为单独的xml

问题描述 投票:0回答:2

我有一个xml输入,其中包含一个xml子节点列表。我想基于xml子节点分离这个xml。但是在分离时,需要保留父节点。我尝试使用for-each,但输出并不像预期的那样。

输入

<node1>
   <id>1</id>
   <code>abcd</code>
   <version>v1</version>
   <node2>
      <market>india</market>
      <active>true</active>
   </node2>
   <node2>
      <market>US</market>
      <active>true</active>
   </node2>
   <mixins>
      <node3>
         <ref>MZ-SR-P004</ref>
         <type>Commercial</type>
      </node3>
   </mixins>
</node1>

预期产出

<node1>
   <id>1</id>
   <code>abcd</code>
   <version>v1</version>
   <node2>
      <market>india</market>
      <active>true</active>
   </node2>
   <mixins>
      <node3>
         <ref>MZ-SR-P004</ref>
         <type>Commercial</type>
      </node3>
   </mixins>
</node1>
<node1>
   <id>1</id>
   <code>abcd</code>
   <version>v1</version>
   <node2>
      <market>US</market>
      <active>true</active>
   </node2>
   <mixins>
      <node3>
         <ref>MZ-SR-P004</ref>
         <type>Commercial</type>
      </node3>
   </mixins>
</node1>

是否可以使用xslt来完成它。我尝试了下面的XSLT转换

XSLT

<?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" indent="yes"/>
<xsl:template match="@*|node()">
         <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
         <xsl:apply-templates />
    </xsl:template>
    <xsl:template match="node2">
         <xsl:for-each select="node2">
            <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
         </xsl:for-each>    
    </xsl:template>
</xsl:stylesheet>

我目前的输出如下所示

当前的xml输出

<?xml version="1.0" encoding="UTF-8"?>
<node1>
   <id>1</id>
   1
   <code>abcd</code>
   abcd
   <version>v1</version>
   v1
   <mixins>
      <node3>
         <ref>MZ-SR-P004</ref>
         MZ-SR-P004
         <type>Commercial</type>
         Commercial
      </node3>
      <ref>MZ-SR-P004</ref>
      MZ-SR-P004
      <type>Commercial</type>
      Commercial
   </mixins>
   <node3>
      <ref>MZ-SR-P004</ref>
      MZ-SR-P004
      <type>Commercial</type>
      Commercial
   </node3>
   <ref>MZ-SR-P004</ref>
   MZ-SR-P004
   <type>Commercial</type>
   Commercial
</node1>


 <id>1</id>1
<code>abcd</code>abcd
<version>v1</version>v1


<mixins>
  <node3>
     <ref>MZ-SR-P004</ref>MZ-SR-P004
     <type>Commercial</type>Commercial
  </node3>
     <ref>MZ-SR-P004</ref>MZ-SR-P004
     <type>Commercial</type>Commercial

</mixins>
  <node3>
     <ref>MZ-SR-P004</ref>MZ-SR-P004
     <type>Commercial</type>Commercial
  </node3>
     <ref>MZ-SR-P004</ref>MZ-SR-P004
     <type>Commercial</type>Commercial
xml xslt
2个回答
1
投票

在你的模板匹配node2然后你做一个xsl:for-each选择node2,但那将寻找你匹配的当前node2的子元素,所以没有任何选择。

你的模板应该选择node1。然后,在xsl:for-each中,您需要创建node1并复制所有子节点,这些子节点是当前的node2或不同名称的节点

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="node1">
        <xsl:for-each select="node2">
            <node1>
                <xsl:apply-templates select="../*[generate-id() = generate-id(current()) or not(self::node2)]" />
            </node1>
        </xsl:for-each>    
    </xsl:template>
</xsl:stylesheet>

注意我还从身份模板中删除了<xsl:apply-templates />


1
投票

一个更通用的XSLT 2或3方法是选择节点(例如node1/node2),然后通过一个模式推送完整的树,使用存储当前node2的隧道参数进行身份复制,以确保该模式何时匹配node2输出这个特殊的node2并忽略所有其他:

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

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:mode name="reconstruct" on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <xsl:for-each select="node1/node2">
        <xsl:apply-templates select="/" mode="reconstruct">
            <xsl:with-param name="copy" tunnel="yes" select="current()"/>
        </xsl:apply-templates>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="node2" mode="reconstruct">
      <xsl:param name="copy" tunnel="yes"/>
      <xsl:sequence select=".[. is $copy]"/>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/gWmuiJF

© www.soinside.com 2019 - 2024. All rights reserved.