#xslt
#xslt
Вопрос:
У меня есть XML-файл, который содержит следующую разметку
<xml>
<content relationship="regula">
**<source attribute1="RSC1985s5c1" attribute2="6(17)"/>**
<target attribute1="LRC1985s5c1" attribute1="6(17)1"/>
</content>
<content relationship="translation-of">
**<source attribute1="RSC1985s5c1" attribute2="6(17)"/>**
<target attribute1="LRC1985s5c4" attribute2="6(17)1"/>
</content>
<content relationship="translation-of">
**<source attribute1="RSC1985s5c2" attribute2="7(17)"/>**
<target attribute1="LRC1985s5c2" attribute2="7(17)"/>
</content>
<content relationship="translation-of">
**<source attribute1="RSC1985s5c1" attribute2="6(17)"/>**
<target attribute1="LRC1985s5c6" attribute2="6(17)2"/>
</content>
</xml>
Я хочу объединить содержимое узлов в один новый узел, если значения attribute1 и attrbite2 исходных узлов равны. Таким образом, результат должен быть следующим
<xml>
<transformed relationship="merged">
<source attribute1="RSC1985s5c1" attribute2="6(17)"/>
<target attribute1="LRC1985s5c1" attribute2="6(17)1"/>
<target attribute1="LRC1985s5c4" attribute2="6(17)1"/>
<target attribute1="LRC1985s5c6" attribute2="6(17)2"/>
</transformed>
<transformed relationship="non-merged">
<source attribute1="RSC1985s5c2" attribute2="7(17)"/>
<target attribute1="LRC1985s5c2" attribute2="7(17)"/>
</transformed>
</xml>
Итак, первые два узла имеют исходные значения attribute1 и attribute2, равные друг другу, поэтому я объединил их как новый узел. Третий узел в исходном коде не совпадает с другими, поэтому я вывел это отдельно. Я пытался использовать цикл foreach, но не смог правильно обойти. Благодарим вас за помощь, если мы сможем добиться этого с помощью сопоставления шаблонов.
Любые узлы содержимого с одинаковым атрибутом дочернего узла «источник» должны быть сгруппированы вместе независимо от их положения. Связь будет изменена на «объединенную» для объединенных и не объединенных элементов, она будет «не объединена»
Комментарии:
1. @_atif: должны ли быть объединены любые два
content
узла с «общими» дочерними элементами? Нужно ли объединять только два соседнихcontent
узла? Что, если более двухcontent
узлов имеют «общие» элементы?relation
Действительно ли атрибут должен быть потерян в результате слияния? В этом вопросе слишком много неясного. Пожалуйста, отредактируйте и предоставьте недостающую информацию.2. Любые узлы содержимого с одинаковым атрибутом дочернего узла «источник» должны быть сгруппированы вместе независимо от их положения. Связь будет изменена на «объединенную» для объединенных и не объединенных элементов, она будет «не объединена»
3. @_atif: Ну, это хорошо сказать в комментарии, но это относится к вопросу — пожалуйста, отредактируйте свой вопрос и предоставьте эту информацию там. Кроме того, вы не ответили на мой вопрос, каким должен быть ожидаемый выходной идентификатор, который необходимо объединить более чем с двумя узлами — пожалуйста, укажите такой пример в своем вопросе. Я определенно не хочу догадываться о вещах, о которых вы, возможно, даже не подумали…
Ответ №1:
Это может быть достигнуто группировкой Muenchian
Поскольку вам необходимо сопоставить два отдельных атрибута исходного элемента, вам может потребоваться использовать объединенный ключ, например
<xsl:key name="dupes"
match="content/source"
use="concat(@attribute1, '|', @attribute2)" />
Важно выбрать объединяющий символ для разделения двух атрибутов (в данном случае канала), который никогда не может появиться в двух значениях атрибута.
Обычно, чтобы сопоставить первый элемент в каждой группе, вы можете сделать это
<xsl:apply-templates select="content/source
[generate-id() =
generate-id(key('dupes', concat(@attribute1, '|', @attribute2))[1])]" />
Однако вам потребуется проделать немного дополнительной работы, так как вам нужно знать, какие исходные элементы содержат несколько элементов в группе, а какие состоят только из отдельных элементов. Итак, чтобы получить группы с несколькими элементами, вы можете сделать следующее:
<xsl:apply-templates select="content/source
[generate-id() =
generate-id(key('dupes', concat(@attribute1, '|', @attribute2))[1])]
[count(key('dupes', concat(@attribute1, '|', @attribute2))) > 1]" />
Вот полный XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="dupes" match="content/source" use="concat(@attribute1, '|', @attribute2)"/>
<xsl:template match="/xml">
<xsl:copy>
<transformed relationship="merged">
<xsl:apply-templates select="content/source[generate-id() = generate-id(key('dupes', concat(@attribute1, '|', @attribute2))[1])][count(key('dupes', concat(@attribute1, '|', @attribute2))) amp;> 1]"/>
</transformed>
<transformed relationship="non-merged">
<xsl:apply-templates select="content/source[generate-id() = generate-id(key('dupes', concat(@attribute1, '|', @attribute2))[1])][count(key('dupes', concat(@attribute1, '|', @attribute2))) = 1]"/>
</transformed>
</xsl:copy>
</xsl:template>
<xsl:template match="source">
<xsl:copy-of select="."/>
<xsl:copy-of select="key('dupes', concat(@attribute1, '|', @attribute2))/following-sibling::target[1]"/>
</xsl:template>
</xsl:stylesheet>
При применении к вашему образцу XML выводится следующее
<xml>
<transformed relationship="merged">
<source attribute1="RSC1985s5c1" attribute2="6(17)"/>
<target attribute1="LRC1985s5c1" attribute2="6(17)1"/>
<target attribute1="LRC1985s5c4" attribute2="6(17)1"/>
<target attribute1="LRC1985s5c6" attribute2="6(17)2"/>
</transformed>
<transformed relationship="non-merged">
<source attribute1="RSC1985s5c2" attribute2="7(17)"/>
<target attribute1="LRC1985s5c2" attribute2="7(17)"/>
</transformed>
</xml>