Сортировка XML с использованием XSLT с сохранением нескольких комментариев - PullRequest
1 голос
/ 15 ноября 2010

Я пытаюсь отсортировать документ XML с помощью XSLT и хочу оставить комментарии. Пока все хорошо, поскольку уже есть некоторые ответы на этот вопрос (см. Связанный ..). Но! ни один из этих (превосходных) ответов не относится к XML, который выглядит следующим образом:

<xml>
    <beatles>
        <!-- comment(1): john is actually my favourite -->
        <!-- comment(2): John died tragically in 1980 -->
        <beatle name="John"/>

        <beatle name="Ringo"/>

        <beatle name="George"/>

        <!-- comment(1): Paul still does live concerts to this day -->
        <!-- comment(2): contrary to common folklore, Paul is NOT dead! -->
        <beatle name="Paul"/>
    </beatles>
</xml>

Что происходит сейчас? Я хочу отсортировать «Битлз» (да благословит их Бог) по имени, а также оставить ВСЕ комментарии каждого «Битлз» на месте, чтобы получить такой результат:

<xml>
    <beatles>
        <beatle name="George"/>

        <!-- comment(1): john is actually my favourite -->
        <!-- comment(2): John died tragically in 1980 -->
        <beatle name="John"/>

        <!-- comment(1): Paul still does live concerts to this day -->
        <!-- comment(2): contrary to common folklore, Paul is NOT dead! -->
        <beatle name="Paul"/>

        <beatle name="Ringo"/>
    </beatles>
</xml>

Старый добрый previous-sibling :: comment () [1] здесь работать не будет. В обычном коде я просто делаю обратный цикл над всеми предыдущими комментариями и останавливаюсь, когда я нажимаю на узел без комментариев; но, как мы все знаем, XSLT для каждого не может быть экранирован.

Есть мысли?

ТИА!

DF.

Ответы [ 2 ]

1 голос
/ 15 ноября 2010

Я думаю, что это может быть достигнуто с помощью клавиши, которая перечисляет все комментарии для данного элемента «битл».

<xsl:key name="comments" match="comment()" use="following-sibling::beatle[1]/@name" />

Так, для каждого комментария он индексируется первым последовательным элементом битла.

Затем вы можете использовать это, чтобы перечислить все комментарии для любого элемента beatle.

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

   <xsl:key name="comments" match="comment()" use="following-sibling::beatle[1]/@name" />

   <xsl:template match="/xml/beatles">
      <beatles>
         <xsl:for-each select="beatle">
            <xsl:sort select="@name" />

            <!-- Loop through all comments for the beatle element -->
            <xsl:for-each select="key('comments', @name)">
               <xsl:comment>
                  <xsl:value-of select="." />
               </xsl:comment>
            </xsl:for-each>

            <!-- Copy the beatle element -->
            <xsl:copy>
               <xsl:copy-of select="@*" />
            </xsl:copy>
         </xsl:for-each>
      </beatles>
   </xsl:template>

</xsl:stylesheet>
0 голосов
/ 15 ноября 2010

При копировании соответствующего узла beatle также следует применять его комментарии. Это все, что вам нужно сделать.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="beatles">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="beatle">
                <xsl:sort select="@name" data-type="text"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="beatle">
        <xsl:variable name="current" select="."/>
        <xsl:apply-templates
                select="preceding-sibling::comment()[generate-id(following-sibling::beatle[1]) = generate-id($current)]"/>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>


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

Выход:

<?xml version="1.0" encoding="windows-1251"?>
<xml>
    <beatles>
        <beatle name="George"/>
        <!-- comment(1): john is actually my favourite -->
        <!-- comment(2): John died tragically in 1980 -->
        <beatle name="John"/>
        <!-- comment(1): Paul still does live concerts to this day -->
        <!-- comment(2): contrary to common folklore, Paul is NOT dead! -->
        <beatle name="Paul"/>
        <beatle name="Ringo"/>
    </beatles>
</xml>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...