2010-11-15 3 views
1

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

<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> 

Что происходит сейчас? Я хочу, чтобы отсортировать Beatles (да благословит их) по имени, а также сохранить все комментарии каждого битла на месте, для того, чтобы получить этот результат:

<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> 

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

Любые мысли?

TIA!

DF.

+0

Хороший вопрос, +1. Я думаю, что @ Tim-C ​​дал вам идеальный ответ. –

ответ

0

При копировании соответствующего узла 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> 
+0

Это подход, который я бы взял, хотя он начнет работать довольно плохо, если будет 11 000 битлов. –

+0

Хорошая форма, все! Я закончил использование решения @Alex Николаенкова, так как моя проблема была немного сложнее, чем заказывать одни и те же узлы - у меня есть несколько разных узлов, с группами групп узлов, которые нужно заказать, поэтому решение Alex было лучше. @ Tim-C ​​- спасибо за ваш ответ, так как я узнал немного больше о XSLT (который я начал изучать только вчера). Еще раз спасибо! – deebugger

+0

@Robert Rossney - возможно, так, но моя проблема не связана с множеством узлов, поэтому я с удовольствием использую ее. – deebugger

1

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

<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

ИМО, использующий ключи для такой простой задачи, является излишним. BTW, когда вы используете XSLT императивного стиля, вы получаете более тугое соединение, и модификации такого кода становятся все труднее и труднее со временем. –

+0

+1 для идеального ответа! –

+0

@ Alex-Nikolaenkov: Ключи - правильный инструмент для правильной ситуации - и * эта * ситуация правильная для использования ключей. –

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