Объединение / объединение аналогичной XML-структуры в одном файле

У меня есть следующая структура в XML-файле:

<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="sowhat">
    </layer2>
  </layer1>
</root>
<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="justit">
    </layer2>
  </layer1>
</root>
<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="yeaha">
    </layer2>
  </layer1>
</root>
<root name="name2123">
  <layer1 name="name2">
    <layer2 attribute="itis">
    </layer2>
  </layer1>
</root>

И я хочу получить результат, который выглядит следующим образом:

<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="sowhat"></layer2>
    <layer2 attribute="justit"></layer2>
    <layer2 attribute="yeaha"></layer2>
  </layer1>
</root>
<root name="name2123">
  <layer1 name="name2">
    <layer2 attribute="itis">
    </layer2>
  </layer1>
</root>

Поэтому я хочу объединить и объединить узлы, насколько это возможно. Я еще не использую XSLT, пробовал, но я не понимаю, даже общая идея. Любые другие идеи или инструменты?

Спасибо

1 ответ

Для чего это стоит, вот способ сделать это в XSLT 1.0.

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

  <xsl:key name="name" match="*[@name]" use="
    concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
  " />

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

  <xsl:template match="*[@name]">
    <xsl:variable name="myKey" select="
      concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
    " />
    <xsl:variable name="myGroup" select="key('name', $myKey)" />

    <xsl:if test="generate-id() = generate-id($myGroup[1])">
      <xsl:copy>
        <xsl:copy-of select="@*" />
        <xsl:apply-templates select="$myGroup/*" />
      </xsl:copy>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

выходы

<roots>
  <root name="name1">
    <layer1 name="name2">
      <layer2 attribute="sowhat"/>
      <layer2 attribute="justit"/>
      <layer2 attribute="yeaha"/>
    </layer1>
  </root>
  <root name="name2123">
    <layer1 name="name2">
      <layer2 attribute="itis"/>
    </layer1>
  </root>
</roots>

Ключевой особенностью XSLT является возможность выражать сложные преобразования в относительно небольшом количестве строк кода. Вышеуказанное преобразование состоит из 29 строк кода, и вы можете сжать его еще больше.

Я думаю, что ускоренный курс в XSLT выходит за рамки этого ответа. Кроме того, в XSLT существует бесчисленное множество курсов ускоренного обучения, доступных по всему Интернету.

Поэтому я дам общий обзор того, что здесь происходит.

Во-первых, я определил два класса элементов для вашего ввода: те, которые могут быть объединены, и те, которые нет. Я определил все элементы, которые имеют @name атрибут для возможности слияния.

  1. Все нормальные узлы (без @name) копируются как есть. Первый <xsl:template> делает это (это шаблон идентичности).
  2. Я определил "объединяемую группу" элементов как те, которые имеют общий набор @name значения атрибутов вдоль своих предков.
    • Для этого я создаю объединение всех соответствующих @name атрибуты для всех элементов, которые имеют их.
    • В настоящее время это преобразование может обрабатывать группы, которые имеют 3 уровня глубины (concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)).
    • Добавьте больше уровней таким же образом, если это необходимо.
    • Имя группы (ключ) для родителя sowhat является name2|name1||это относится и к другим <layer2> в этой логической группе.
  3. Теперь всякий раз, когда механизм XSLT встречает элемент с @name, Это
    • вычисляет ключ для этого элемента ($myKey).
    • получает группу элементов с одинаковым ключом ($myGroup).
    • выясняет, является ли текущий элемент первым элементом в группе, если это так, он копирует его в вывод
    • эффективно это группирует элементы по их ключу (эта техника называется группировкой по мюнхену).
    • затем он делает рекурсивный шаг: он начинает обрабатывать потомков этой группы ($myGroup/*).
    • фактически это возвращает нас к квадрату 0, и алгоритм начинается с самого начала.

В моем коде есть некоторые предположения / ограничения, которые могут не совпадать с вашими данными.

  • Элементы должны быть объединены их @name а не какой-то другой собственностью.
  • Элементы с одинаковым @name Родословная не имеет специальных атрибутов, поэтому отбрасывание каждого элемента, кроме первого в определенной группе, не приведет к потере данных.
  • Существует конечная глубина вложения.
  • Объединяемые элементы никогда не являются потомками не объединяемых элементов (нет <layer> с @name внутри <layer> без @name)
  • Вероятно, другие, которые прямо сейчас забивают мне голову.

Чтение рекомендаций

  • сопоставление с шаблоном и общие рабочие механизмы процессора XSLT
  • Правила XSL по умолчанию
  • XPath
  • XSL-ключи и мюнхенская группировка
  • шаблон идентичности
  • концепция текущего узла во всем потоке обработки
Другие вопросы по тегам