Преобразование xslt из XML в XML с использованием группировки по узлу и атрибуту - PullRequest
0 голосов
/ 31 января 2019

Мне нужна помощь по преобразованию xml в другой формат xml с использованием xslt.Попробовал использовать .xsl файл ниже, но он не работает, оцените помощь.

 <?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="Mappings/Source/MapToType/MapTo/*">
  <xsl:copy>
      <xsl:for-each-group select="Source" group-by="name">
          <xsl:apply-templates select="." />
      </xsl:for-each-group>
  </xsl:copy>
  </xsl:template>

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

Ниже приведен исходный XML

  <?xml version='1.0' encoding='UTF-8'?>
   <Mappings version="1.0">
   <Source name="testA" type="testType" reg="Good">
    <MapToType type="Tiger">
        <MapTo name="Org" reg="Ver1.0"/>
    </MapToType>
   </Source>
  <Source name="testB" type="testType" reg="Good">
    <MapToType type="Tiger">
        <MapTo name="Org2" reg="Ver2.0"/>
    </MapToType>
  </Source>
  <Source name="testA" type="testType" reg="Good">
    <MapToType type="Tiger">
        <MapTo name="Org3" reg="Ver3.0"/>
    </MapToType>
   </Source>
</Mappings>

Вывод ожидается как показано ниже.

 <Mappings version="1.0">
 <Source name="testA" type="testType" reg="Good">
    <MapToType type="Tiger">
        <MapTo name="Org" reg="Ver1.0"/>
        <MapTo name="Org3" reg="Ver3.0"/>
    </MapToType>
  </Source>
  <Source name="testB" type="testType" reg="Good">
    <MapToType type="Tiger">
       <MapTo name="Org2" reg="Ver2.0"/>
    </MapToType>
  </Source>
  </Mappings>

У кого-нибудь есть решение, как написать условие для отображения в виде output.xml?

1 Ответ

0 голосов
/ 31 января 2019

Первое замечание: xsl:for-each-group - это команда XSLT 2.0, поэтому вам следует убедиться, что вы используете процессор, который может обрабатывать XSLT 2.0

В любом случае, одна из причин, по которой он не работает, заключается в том, что когда вы делаете<xsl:for-each-group select="Source" group-by="name">, вы находитесь в шаблоне, который соответствует MapTo.Поскольку выбор будет относиться к этому элементу MapTo, вы будете искать дочерние элементы с именем Source, которых нет.

(РЕДАКТИРОВАТЬ: Или, как справедливо указывает Мартин Хоннен в комментарияхшаблон действительно соответствует дочерним элементам MapTo, а не MapTo сам по себе, и поэтому не будет ничего совпадать, и поэтому никогда не будет использоваться ....)

Вам действительно следует изменить свой шаблон насоответствует Mappings вместо ...

<xsl:template match="Mappings">
  <xsl:copy>
    <xsl:apply-templates select="@*" />
     <xsl:for-each-group select="Source" group-by="@name">

Обратите внимание, что если в сгруппированных элементах Source у вас могут быть элементы MapToType с разными типами, вам может понадобиться вложенный xsl:for-each-group внутри этого элемента..

Попробуйте этот XSLT ....

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

  <xsl:template match="Mappings">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:for-each-group select="Source" group-by="@name">
        <xsl:copy>
          <xsl:apply-templates select="@*" />
          <xsl:for-each-group select="current-group()/MapToType" group-by="@type">
            <xsl:copy>
             <xsl:apply-templates select="@*" />
             <xsl:apply-templates select="current-group()/MapTo" />
            </xsl:copy>
          </xsl:for-each-group>
        </xsl:copy>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

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

В качестве альтернативы, если MapToType всегда будет иметь одинаковые type для каждого сгруппированного элемента Source, вы можете упроститьXSLT к этому ..

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

  <xsl:template match="Mappings">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:for-each-group select="Source" group-by="@name">
        <xsl:copy>
          <xsl:apply-templates select="@*" />
          <MapToType>
            <xsl:apply-templates select="MapToType/@*" />
            <xsl:apply-templates select="current-group()/MapToType/MapTo" />
          </MapToType>
        </xsl:copy>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

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

РЕДАКТИРОВАТЬ: Если вы используете только XSLT 1.0, то вам нужно использовать технику под названием Muenchian Grouping.Это будет подавляющим, если вы новичок в XSLT, особенно в этом случае, если у вас есть вложенная группировка, которая должна учитывать родительский элемент.

Попробуйте этот XSLT затем:

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

  <xsl:key name="Sources" match="Source" use="@name" />
  <xsl:key name="MapToTypes" match="MapToType" use="concat(../@name, @type)" />

  <xsl:template match="Mappings">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:for-each select="Source[generate-id() = generate-id(key('Sources', @name)[1])]">
        <xsl:copy>
          <xsl:apply-templates select="@*" />
          <xsl:for-each select="key('Sources', @name)/MapToType[generate-id() = generate-id(key('MapToTypes', concat(../@name, @type))[1])]">
            <xsl:copy>
             <xsl:apply-templates select="@*" />
             <xsl:apply-templates select="key('MapToTypes', concat(../@name, @type))/MapTo" />
            </xsl:copy>
          </xsl:for-each>
        </xsl:copy>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

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

См.это в действии на http://xsltfiddle.liberty -development.net / jyRYYhX

Читайте о мюнхенской группировке на http://www.jenitennison.com/xslt/grouping/muenchian.html. Затем прочитайте это снова.И снова ....

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