объединение элементов с помощью xsl

#xml #xslt #merge

#xml #xslt #слияние

Вопрос:

У меня есть несколько XML-элементов, которые фактически ссылаются на один и тот же «объект», они могут иметь одни и те же данные или могут иметь разные данные. У любого могут быть элементы, которых нет у других. Я хочу, чтобы мой xsl выводил сумму элементов всех этих xml-«объектов». Мы не будем беспокоиться о перекрытии. Как вы можете выполнить подобное слияние с помощью XSL?

Пример:

 <root>
<object>
<property1>value</property1>
</object>
<object>
<property1>value</property1>
<property2>value</property2>
</object>
...
<object>
<propertyN>value</propertyN>
</object>
</root>
  

Результат:

 <root>
<object>
<property1>value</property1>
<property2>value</property2>
...
<propertyN>value</propertyN>
</object>
</root>
  

Комментарии:

1. Сначала вы говорите, что вам нужна «сумма» всех элементов, затем вы говорите, что вас не будет беспокоить «перекрытие». Я нахожу это противоречивым. Если у вас есть N /root/object/property1, что вы хотите в качестве результата?

2. Если есть 2 «свойства1», я не беспокоюсь о том, что там происходит (пока), это может быть комбинация, первая или последняя. Я не беспокоюсь об этом сейчас, потому что для этого нужно будет написать что-то более сложное. Сначала я убираю «простую» часть. Под простым я подразумеваю часть без конфликтов.

3. @aepeus. Хорошо, является ли XSLT строгим требованием? Вероятно, гуру XSLT могут это сделать, но я бы выбрал библиотеку, похожую на DOM.

Ответ №1:

Это преобразование применяется к вашему sample .xml

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

<xsl:template match="/">
<root>
  <object>
    <xsl:for-each select="/root/object//*">
      <xsl:copy-of select="."/>
    </xsl:for-each>
  </object>
</root>
</xsl:template>
</xsl:stylesheet>
  

Выдает этот вывод :

 <?xml version="1.0" encoding="UTF-8"?>
<root>
<object>
  <property1>value</property1>
  <property1>value</property1>
  <property2>value</property2>
  <propertyN>value</propertyN>
</object>
</root>
  

Хотя позже вы, вероятно, захотите сделать что-то лучше, это должно заставить вас двигаться дальше.

Ответ №2:

Это может быть достигнуто группировкой по Меншиану.

Сначала определите ключ, соответствующий элементам свойств (в данном случае я предполагаю, что все дочерние узлы объекта являются свойствами), используя имя в качестве справочного.

Далее вам нужно сопоставить первое вхождение каждого имени свойства, проверив, что это первое такое свойство в справочном ключе

 <xsl:apply-templates 
 select="//object/*[generate-id() = generate-id(key('property', local-name())[1])]" />
  

Затем вы можете просто скопировать такие совпадения.

Вот полный XSLT

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

   <xsl:key name="property" match="object/*" use="local-name()"/>

   <xsl:template match="/">
      <object>
         <xsl:apply-templates select="//object/*[generate-id() = generate-id(key('property', local-name())[1])]"/>
      </object>
   </xsl:template>

   <xsl:template match="*">
      <xsl:copy-of select="."/>
   </xsl:template>

</xsl:stylesheet>
  

При применении к вашему образцу XML вывод выглядит следующим образом:

 <object>
<property1>value</property1>
<property2>value</property2>
<propertyN>value</propertyN>
</object>
  

В этом случае возвращается только первое вхождение имени свойства. Если вы хотите объединить элементы, вы могли бы, например (предполагая, что все значения были числовыми), суммировать их

 <xsl:template match="*">
  <xsl:copy>
    <xsl:value-of select="sum(key('property', local-name()))" />
  </xsl:copy>
</xsl:template>
  

Итак, учитывая этот входной XML….

 <root> 
<object> 
<property1>1</property1> 
</object> 
<object> 
<property1>2</property1> 
<property2>3</property2> 
</object> 
... 
<object> 
<propertyN>4</propertyN> 
</object> 
</root> 
  

Результат был бы таким…

 <object>
<property1>3</property1>
<property2>3</property2>
<propertyN>4</propertyN>
</object>
  

Комментарии:

1. Спасибо, это, скорее всего, тоже окажется полезным.