Преобразовать xml, содержащий список дочерних узлов, в отдельный xml - PullRequest
0 голосов
/ 31 августа 2018

У меня есть ввод 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

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Более общий подход 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

0 голосов
/ 31 августа 2018

В вашем шаблоне соответствия 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 /> из шаблона идентификации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...