2015-09-22 3 views
0

После первого преобразования XSL У меня есть выход XML, похожий на следующий:Как объединить узлы на основе значения атрибута?

<?xml version="1.0" encoding="UTF-8"?> 
<analysis type="1"> 
    <file path="a.txt"> 
     <line nb="23" found="true"/> 
     <line nb="36" found="true" count="2"/> 
     <line nb="98" found="true"/> 
    </file> 
    <file path="a.txt"> 
     <line nb="100" found="false"/> 
    </file> 
    <file path="b.txt"> 
     <line nb="10" found="false"/> 
    </file> 
    <!-- more file nodes below with different @path --> 
</analysis> 

Но теперь мне нужно, чтобы получить второй выход, где file узлы объединены, если они имеют один и тот же атрибут path следующим образом:

<?xml version="1.0" encoding="UTF-8"?> 
<analysis type="1"> 
    <file path="a.txt"> 
     <line nb="23" found="true"/> 
     <line nb="36" found="true" count="2"/> 
     <line nb="98" found="true"/> 
     <line nb="100" found="false"/> 
    </file> 
    <file path="b.txt"> 
     <line nb="10" found="false"/> 
    </file> 
</analysis> 

Не знаю, возможно @path значения заранее.

Я просмотрел несколько сообщений о слиянии узлов, но не смог найти способ делать то, что хочу. Я потерялся с группировкой узлов, ключами, генерации id ... и только получил сообщения об ошибках.

Не могли бы вы помочь мне получить второй выход, начиная с первого (с xls 1.0)? И если бы вы могли предоставить некоторые ссылки (сайты), где я мог бы найти объяснения в отношении таких преобразований, это было бы действительно здорово.

Примечание: атрибут двух line узлов двух file узлов, имеющих один и тот же @path никогда не конфликтуют @nb, он уникален, то это никогда не произойдет:

<?xml version="1.0" encoding="UTF-8"?> 
<analysis type="1"> 
    <file path="a.txt"> 
     <line nb="36" found="true" count="2"/> 
    </file> 
    <file path="a.txt"> 
     <line nb="36" found="true"/> 
    </file> 
</analysis> 

Спасибо большое за помощь!

+0

Вы прочитали статью: http://www.jenitennison.com/xslt/grouping/muenchian.html Если да, то где именно ваши трудности? –

+0

Спасибо за ссылку. Я не знал об этом. Я прочитаю его внимательно. – Kraal

ответ

2

XPath 1.0 без ключей

Поскольку вы заявляете в вашем вопросе, что у вас есть проблемы с пониманием ключей, вот один из способов сделать это без ключей, используя технику, называемую родственными рекурсиями. Он считается менее хорошим, чем использование ключей, поскольку он использует ось брата, которая обычно довольно медленная. Однако, в большинстве практических ситуаций, вы не заметите разницы:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

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

    <xsl:template match="analysis"> 
     <xsl:copy> 
      <xsl:copy-of select="@*" /> 
      <xsl:apply-templates select="file[not(preceding-sibling::file/@path = @path)]" mode="sibling-recurse" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="file" mode="sibling-recurse"> 
     <xsl:copy> 
      <!-- back to default mode --> 
      <xsl:apply-templates select="node() | @*" /> 
      <xsl:apply-templates select="following-sibling::file[current()/@path = @path]" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="file"> 
     <xsl:apply-templates select="node()" /> 
    </xsl:template> 
</xsl:stylesheet> 

XPath 1.0 с ключами для Münchian Группирование

Этот подход использует Münchian Группировка, что объясняется в другом месте (только следить за учебники like this one с этим код в руке). Он также использует ось брата, но гораздо менее разрушительным способом (т. Е. Не требуется пересекать всю ось брата на каждом узле).

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

    <xsl:key match="file" use="@path" name="path" /> 

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

    <xsl:template match="analysis"> 
     <xsl:copy> 
      <xsl:copy-of select="@*" /> 
      <xsl:apply-templates select="file[generate-id(.) = generate-id(key('path', @path))]" mode="sibling-recurse" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="file" mode="sibling-recurse"> 
     <xsl:copy> 
      <!-- back to default mode --> 
      <xsl:apply-templates select="node() | @*" /> 
      <xsl:apply-templates select="following-sibling::file[@path = current()/@path]/node()" /> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

Примечание: для обоих подходов, режим переключение не совсем необходимо, но это делает его легче писать простые шаблоны соответствия и предотвращает коллизии приоритетов или дефицитные найти ошибки (IMO).

+0

Большое спасибо (снова) за ваш полный ответ. В настоящее время я не могу попробовать ваше решение (я читаю ваш ответ на своем телефоне), но я сделаю это как можно скорее. С уважением. – Kraal

+1

Работает отлично, я сейчас адаптирую его к своему конкретному контексту. Еще раз спасибо ! – Kraal

+0

Хороший код xslt, плюс один. –

Смежные вопросы