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