2012-04-10 1 views
1

У меня проблема с группировкой записей xml через атрибуты с использованием XSLT.Отсутствует первый элемент для каждого цикла с предшествующим братом в xslt

Вот мой источник XML:

<chron> 
<chronEntry type="education" order="1" blockorder="1"> 
    <foo>bar</foo> 
</chronEntry> 
    <chronEntry type="education" order="2" blockorder="1"> 
<foo>bar</foo> 
    </chronEntry> 
<chronEntry type="education" order="3" blockorder="1"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="communityservice" order="1" blockorder="2"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="experience" order="1" blockorder="3"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="experience" order="2" blockorder="3"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="experience" order="3" blockorder="3"> 
    <foo>bar</foo> 
</chronEntry> 
<chronEntry type="experience" order="4" blockorder="3"> 
    <foo>bar</foo> 
</chronEntry> 
</chron> 

Что я хочу, чтобы получить список всех доступных значений «типа» атрибута. В этом случае он должен быть: - образование - обязательные работы - опыт

Я судимое это так:

<xsl:for-each select="/foobar/chron/chronEntry"> 
      <xsl:sort select="@blockorder"/> 
       <xsl:if test ="@blockorder != preceding-sibling::chronEntry[1]/@blockorder"> 
        <fo:table-row> 
         <fo:table-cell> 
          <fo:block><xsl:value-of select="@type"/></fo:block> 
         </fo:table-cell> 
        </fo:table-row> 
       </xsl:if> 
      </xsl:for-each> 

, что я получаю: - обязательные работы - опыт

Я m отсутствует «образование» (первый)

Что я могу сделать, чтобы получить его?

Thaks для вашей помощи!

Greetz

Dave

+0

Вы используя XSLT 1.0 или XSLT 2.0? –

ответ

1

Проблема заключается в том, что, хотя вы создаете отсортированный список-узлов, то preceding-sibling:: (или любую ось) может быть использована только для выражения отношения между узлами в документе (не в список узлов).

Поэтому preceding-sibling:: chronEntry [1] selects the first preceding sibling chronEntry` контекстного узла в текущем документе - не в отсортированном список-узлов.

Решение:

  1. В XSLT 1.0 захватить результат xsl:for-each в переменной. Поскольку это относится к печально известному типу RTF, вы должны преобразовать его в обычное дерево, используя функцию расширения xxx:node-set(), поддерживаемую используемым процессором XSLT 1.0. Затем в этом регулярном дереве оси, включая preceding-sibling::, имеют желаемый смысл.

  2. Рекомендованное решение. Используйте Muenchian группировку:

так:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kType" match="@type" use="."/> 

<xsl:template match= 
    "chronEntry 
    [generate-id(@type) 
    = 
    generate-id(key('kType', @type)[1]) 
    ]"> 
    <xsl:value-of select="concat(@type, ' ')"/> 
</xsl:template> 
<xsl:template match="text()"/> 
</xsl:stylesheet> 

, когда это преобразование применяется на поставленном XML документа:

<chron> 
    <chronEntry type="education" order="1" blockorder="1"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="education" order="2" blockorder="1"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="education" order="3" blockorder="1"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="communityservice" order="1" blockorder="2"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="experience" order="1" blockorder="3"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="experience" order="2" blockorder="3"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="experience" order="3" blockorder="3"> 
     <foo>bar</foo> 
    </chronEntry> 
    <chronEntry type="experience" order="4" blockorder="3"> 
     <foo>bar</foo> 
    </chronEntry> 
</chron> 

разыскиваемый, правильный результат производства :

education communityservice experience 
0

Вам действительно нужен xsl: sort? или вы использовали его для группировки?если это так, то вы можете просто удалить XSL: вид и исправить XSL: если тест:

 <xsl:for-each select="/foobar/chron/chronEntry"> 
      <xsl:if test ="not(@blockorder = preceding-sibling::chronEntry/@blockorder)"> 
       <fo:table-row> 
        <fo:table-cell> 
         <fo:block><xsl:value-of select="@type"/></fo:block> 
        </fo:table-cell> 
       </fo:table-row> 
      </xsl:if> 
     </xsl:for-each> 

Если вам нужен XSL: сортируют, вы можете использовать это:

 <xsl:variable name="types" select="/foobar/chron/chronEntry[not(preceding-sibling::*/@[email protected])]"/> 
     <xsl:for-each select="$types"> 
      <xsl:sort select="@blockorder"/> 
      <fo:table-row> 
       <fo:table-cell> 
        <fo:block> 
         <xsl:value-of select="@type"/> 
        </fo:block> 
       </fo:table-cell> 
      </fo:table-row> 
     </xsl:for-each>