Объединение дублирующихся узлов в для формирования нового XML с использованием XSLT - PullRequest
2 голосов
/ 17 июня 2011

У меня есть XML, как показано ниже. Где различные элементы приходят для удаления или добавления. каждый элемент будет иметь серийный номер. то, что я пытаюсь сделать, это я хочу подготовить новый xml из этих входных данных таким образом, чтобы, если элемент с кодом элемента пришел для добавления и удаления, я хочу объединить их в один узел элемента. Новый сформированный элемент будет иметь код действия в качестве обновления, и sino добавит элемент sino, а oldsino удалит элемент sino.

ВХОД

`


<ITEM> 
    <SINO>1</SINO>
    <ITEMCODE>101</ITEMNAME> 
    <ACTION>ADD</ACTION>
    <OLDSINO></OLDSINO>
</ITEM>
<ITEM> 
    <SINO>2</SINO>
    <ITEMCODE>101</ITEMNAME> 
    <ACTION>DELETE</ACTION>
    <OLDSINO></OLDSINO>
</ITEM>
<ITEM> 
    <SINO>3</SINO>
    <ITEMCODE>102</ITEMNAME> 
    <ACTION>ADD</ACTION>
    <OLDSINO></OLDSINO>
</ITEM>
<ITEM> 
    <SINO>4</SINO>
    <ITEMCODE>103</ITEMNAME> 
    <ACTION>ADD</ACTION>
    <OLDSINO></OLDSINO>
</ITEM>
<ITEM> 
    <SINO>5</SINO>
    <ITEMCODE>103</ITEMNAME> 
    <ACTION>DELETE</ACTION>
    <OLDSINO></OLDSINO>
</ITEM>
<ITEM> 
    <SINO>6</SINO>
    <ITEMCODE>104</ITEMNAME> 
    <ACTION>DELETE</ACTION>
    <OLDSINO></OLDSINO>
</ITEM>

`

OUTPUT

`


<ITEM> 
    <SINO>1</SINO>
    <ITEMCODE>101</ITEMNAME> 
    <ACTION>UPDATE</ACTION>
    <OLDSINO>2</OLDSINO>
</ITEM>
<ITEM> 
    <SINO>3</SINO>
    <ITEMCODE>102</ITEMNAME> 
    <ACTION>ADD</ACTION>
    <OLDSINO></OLDSINO>
</ITEM>
<ITEM> 
    <SINO>4</SINO>
    <ITEMCODE>103</ITEMNAME> 
    <ACTION>DELETE</ACTION>
    <OLDSINO>5</OLDSINO>
</ITEM>
<ITEM> 
    <SINO>6</SINO>
    <ITEMCODE>104</ITEMNAME> 
    <ACTION>DELETE</ACTION>
    <OLDSINO></OLDSINO>
</ITEM>

`

Любые идеи, как добиться этого с помощью XSLT.

Ответы [ 3 ]

1 голос
/ 17 июня 2011

Если для добавления и удаления пришел элемент с кодом элемента, я хочу объединить его в один элемент. Новый сформированный элемент будет иметь код действия в качестве обновления, и sino добавит элемент sino, а oldsino удалит элемент sino

Это решение в основном работает с шаблонами сопоставления шаблонов для братьев и сестер и использует правило идентификации.

XSLT 1.0

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

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

    <xsl:template match="ITEM[
            ITEMCODE[../ACTION='ADD']
        =
                ../ITEM/ITEMCODE[../ACTION='DELETE']]">
        <xsl:copy>
            <SINO><xsl:value-of select="../ITEM[ITEMCODE
                    =current()/ITEMCODE and ACTION='ADD']/
                    SINO"/>
            </SINO>
            <xsl:copy-of select="ITEMCODE"/>
            <ACTION>UPDATE</ACTION>
            <OLDSINO><xsl:value-of select="../ITEM[ITEMCODE
                    =current()/ITEMCODE and ACTION='DELETE']/
                    SINO"/>
            </OLDSINO>          
        </xsl:copy>
            </xsl:template>

            <xsl:template match="ITEM[
            ITEMCODE[../ACTION='DELETE']
        =
                ../ITEM/ITEMCODE[../ACTION='ADD']]"/>


</xsl:stylesheet>

Решение дает:

<?xml version="1.0" encoding="UTF-16"?>
<ITEMS>
    <ITEM>
        <SINO>1</SINO>
        <ITEMCODE>101</ITEMCODE>
        <ACTION>UPDATE</ACTION>
        <OLDSINO>2</OLDSINO>
    </ITEM>
    <ITEM>
        <SINO>3</SINO>
        <ITEMCODE>102</ITEMCODE>
        <ACTION>ADD</ACTION>
        <OLDSINO></OLDSINO>
    </ITEM>
    <ITEM>
        <SINO>4</SINO>
        <ITEMCODE>103</ITEMCODE>
        <ACTION>UPDATE</ACTION>
        <OLDSINO>5</OLDSINO>
    </ITEM>
    <ITEM>
        <SINO>6</SINO>
        <ITEMCODE>104</ITEMCODE>
        <ACTION>DELETE</ACTION>
        <OLDSINO></OLDSINO>
    </ITEM>
</ITEMS>
1 голос
/ 17 июня 2011

Вот краткое и простое решение, которое переопределяет правило / шаблон идентификации:

<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:key name="kItemByCode" match="ITEM"
  use="ITEMCODE"/>

 <xsl:key name="kActionByCode" match="ACTION"
  use="../ITEMCODE"/>

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

 <xsl:template match=
  "ITEM[not(generate-id() =
            generate-id(key('kItemByCode', ITEMCODE)[1])
            )
        ]"/>

 <xsl:template match=
   "ITEM[generate-id() =
         generate-id(key('kItemByCode', ITEMCODE)[1])
        and
         key('kActionByCode', ITEMCODE) = 'ADD'
        and
         key('kActionByCode', ITEMCODE) = 'DELETE'
        ]
        /ACTION/text()
   ">
        <xsl:text>UPDATE</xsl:text>
  </xsl:template>

 <xsl:template match=
   "ITEM[generate-id() =
         generate-id(key('kItemByCode', ITEMCODE)[1])
        and
         key('kActionByCode', ITEMCODE) = 'ADD'
        and
         key('kActionByCode', ITEMCODE) = 'DELETE'
        ]
        /OLDSINO
   ">
    <OLDSINO>
     <xsl:apply-templates mode="List"
      select="key('kItemByCode', ../ITEMCODE)[position()>1]" />
    </OLDSINO>
  </xsl:template>

 <xsl:template match="ITEM" mode="List">
  <xsl:if test="not(position()=1)">,</xsl:if>
  <xsl:value-of select="SINO"/>
 </xsl:template>
</xsl:stylesheet>

, когда это преобразование применяется к следующему документу XML (на основании и исправлении предоставленного сильно искаженного фрагмента XML):

<t>
    <ITEM>
        <SINO>1</SINO>
        <ITEMCODE>101</ITEMCODE>
        <ACTION>ADD</ACTION>
        <OLDSINO></OLDSINO>
    </ITEM>
    <ITEM>
        <SINO>2</SINO>
        <ITEMCODE>101</ITEMCODE>
        <ACTION>DELETE</ACTION>
        <OLDSINO></OLDSINO>
    </ITEM>
    <ITEM>
        <SINO>3</SINO>
        <ITEMCODE>102</ITEMCODE>
        <ACTION>ADD</ACTION>
        <OLDSINO></OLDSINO>
    </ITEM>
    <ITEM>
        <SINO>4</SINO>
        <ITEMCODE>103</ITEMCODE>
        <ACTION>ADD</ACTION>
        <OLDSINO></OLDSINO>
    </ITEM>
    <ITEM>
        <SINO>5</SINO>
        <ITEMCODE>103</ITEMCODE>
        <ACTION>DELETE</ACTION>
        <OLDSINO></OLDSINO>
    </ITEM>
    <ITEM>
        <SINO>6</SINO>
        <ITEMCODE>104</ITEMCODE>
        <ACTION>DELETE</ACTION>
        <OLDSINO></OLDSINO>
    </ITEM>
</t>

желаемый, правильный результат:

<t>
  <ITEM>
    <SINO>1</SINO>
    <ITEMCODE>101</ITEMCODE>
    <ACTION>UPDATE</ACTION>
    <OLDSINO>2</OLDSINO>
  </ITEM>
  <ITEM>
    <SINO>3</SINO>
    <ITEMCODE>102</ITEMCODE>
    <ACTION>ADD</ACTION>
    <OLDSINO />
  </ITEM>
  <ITEM>
    <SINO>4</SINO>
    <ITEMCODE>103</ITEMCODE>
    <ACTION>UPDATE</ACTION>
    <OLDSINO>5</OLDSINO>
  </ITEM>
  <ITEM>
    <SINO>6</SINO>
    <ITEMCODE>104</ITEMCODE>
    <ACTION>DELETE</ACTION>
    <OLDSINO />
  </ITEM>
</t>

Объяснение :

  1. Правило / шаблон идентификации копирует каждый узел "как есть".

  2. Шаблон с пустым телом переопределяет правило идентификации длякаждый не первый ITEM из группы ITEM элементов с одинаковым ITEMCODE - ни один такой узел не копируется в вывод (он же удален).

  3. Третий шаблон переопределяет правило идентификации для каждого элемента ITEM, который является первым в группе из ITEM элементов с таким же ITEMCODE и для которого ITEMCODE существуют элементы с ACTION и «ADD», и «УДАЛЯТЬ".Он создает необходимый элемент OLDSINO, применяя шаблоны в режиме «Список» ко всем ITEM элементам в группе, кроме первого.

  4. Метод Мюнхена для группировки и вообщеключи используются для достижения эффективной и компактной реализации.

  5. Это решение корректно работает с любой произвольной смесью ITEM элементов, которые могут иметь одинаковые ITEMCODE.

0 голосов
/ 17 июня 2011

Исправление для опечатки (открытие тега ITEMCODE и закрытие тега ITEMNAME) и работа с корневым элементом ITEMS полного 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:key name="deletes" match="ITEM[ACTION='DELETE']" use="ITEMCODE/text()"/>
  <xsl:key name="adds" match="ITEM[ACTION='ADD']" use="ITEMCODE/text()"/>

  <xsl:template match="ITEMS">
    <ITEMS>
      <xsl:apply-templates select="ITEM" />
    </ITEMS>
  </xsl:template>


  <xsl:template match="ITEM[ACTION='ADD' and key('deletes',ITEMCODE/text())]">
        <xsl:variable name="current" select="ITEMCODE/text()"/>
        <xsl:copy>
          <xsl:for-each select="*">
            <xsl:choose>
              <xsl:when test="name()='ACTION'">
                <ACTION>UPDATE</ACTION>
              </xsl:when>
              <xsl:when test="name()='OLDSINO'">
                <OLDSINO><xsl:value-of select="key('deletes',$current)/SINO/text()"/></OLDSINO>
              </xsl:when>
              <xsl:otherwise>
                <xsl:copy-of select="." />
              </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each>
        </xsl:copy>
  </xsl:template>

  <xsl:template match="ITEM[ACTION='ADD' and not(key('deletes',ITEMCODE/text()))]">
    <xsl:copy-of select="." />
   </xsl:template>

  <xsl:template match="ITEM[ACTION='DELETE' and not(key('adds',ITEMCODE/text()))]">
    <xsl:copy-of select="." />
  </xsl:template>

  <xsl:template match="ITEM" />

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