2011-12-02 1 views
2

Это эволюция моего вопроса здесь: Groups two xml files like a sql group-by Приведенный пример и решение Dimitre считали отличное значение isbn. Теперь измените библиотеки XML, чтобы иметь mylibrary.xml:Группы двух xml-файлов, таких как sql group-by [2]

<library> 
    <book id="1" isbn="1"/> 
    <book id="2" isbn="1"/> 
    <book id="3" isbn="2"/> 
    <book id="4" isbn="4"/> 
    <book id="5" isbn="5"/> 
    <book id="6" isbn="4"/> 
    <book id="7" isbn="4"/> 
</library> 

и это тот, который может быть использован: bookreference.xml:

<reference> 
    <book isbn="1"> 
     <category>SF</category> 
    </book> 
    <book isbn="2"> 
     <category>SF</category> 
    </book> 
    <book isbn="3"> 
     <category>SF</category> 
    </book> 
    <book isbn="4"> 
     <category>Comedy</category> 
    </book> 
    <book isbn="5"> 
     <category>Comedy</category> 
    </book> 
</reference> 

я хочу, чтобы получить номера книги, которые я получил в mylibrary ', даже если некоторые имеют одинаковые isbn', groupby category, используя xslt 1-0.

выход хотел:

SF : 3 book(s) 
Comedy : 4 book(s) 

моего XSLT предлагает здесь: Groups two xml files like a sql group-by работает нормально, но, конечно, использовать «для-каждый» цикл и функцию расширения. Наверняка есть лучшее решение.

ответ

1

Снова очень хороший вопрос! (+1)

Это преобразование, с помощью двух ключей для достижения полной эффективности:

<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="kBookByCat" match="book" 
      use="category"/> 

    <xsl:key name="kBookByIsbn" match="book" 
      use="@isbn"/> 

    <xsl:variable name="vDoc" select="/"/> 

    <xsl:variable name="vRef" select= 
    "document('file:///c:/temp/delete/reference.xml')"/> 

    <xsl:variable name="vMyIsbns" select="/*/*/@isbn"/> 

    <xsl:variable name="vResult"> 
     <xsl:apply-templates select="$vRef/*"/> 
    </xsl:variable> 

    <xsl:template match="/"> 
     <xsl:copy-of select="$vResult"/> 
    </xsl:template> 

    <xsl:template match= 
     "book[generate-id() 
      = 
      generate-id(key('kBookByCat', category)[1]) 
      ] 
     "> 
     <xsl:variable name="vBooksinCat" select= 
       "key('kBookByCat', category)"/> 

     <xsl:value-of select="category"/> : <xsl:text/> 
     <xsl:for-each select="$vDoc"> 
      <xsl:value-of select="count(key('kBookByIsbn',$vBooksinCat/@isbn))"/> 
     </xsl:for-each> 
     <xsl:text> book(s)&#xA;</xsl:text> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 

при нанесении на прилагаемом XML документа, содержащегося в файле mylibrary.xml:

<library> 
    <book id="1" isbn="1"/> 
    <book id="2" isbn="1"/> 
    <book id="3" isbn="2"/> 
    <book id="4" isbn="4"/> 
    <book id="5" isbn="5"/> 
    <book id="6" isbn="4"/> 
    <book id="7" isbn="4"/> 
</library> 

с предоставленным XML-документом в C: \ temp \ delete \ reference.xml:

<reference> 
    <book isbn="1"> 
     <category>SF</category> 
    </book> 
    <book isbn="2"> 
     <category>SF</category> 
    </book> 
    <book isbn="3"> 
     <category>SF</category> 
    </book> 
    <book isbn="4"> 
     <category>Comedy</category> 
    </book> 
    <book isbn="5"> 
     <category>Comedy</category> 
    </book> 
</reference> 

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

SF : 3 book(s) 
Comedy : 4 book(s) 
+0

Посмотрите, что вы всегда на шаг впереди: P, хотя по какой-то причине, когда я тестировал решение, совпадение шаблона для 2 уникальных категорий, похоже, не работало (vs2008), пока я не переместил его, и посмотрю, что я имею в виду, если u взглянуть Разница между ответами! – Treemonkey

+0

И снова отличный ответ, огромное спасибо, я упал, как студент, трачу часы на проблемы и свои плохие: никогда не найдя решение, когда вы делаете ... 5 минут? – Seb

+0

У меня еще недостаточно репутации (<100), чтобы ответить на мой вопрос, но через 3 часа я смогу предложить модификацию кода, чтобы не показывать категорию, когда количество книг = 0. – Seb

1

модифицированная версия Dimitri работать для этого

<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kBookByCat" match="book" use="category"/> 

<xsl:variable name="vRef" select="document('file:///c:/temp/delete/reference.xml')"/> 

<xsl:variable name="meh" select="*"/> 

<xsl:template match="/"> 
    <xsl:apply-templates select="$vRef/reference/book[generate-id()=generate-id(key('kBookByCat', category)[1])]" /> 
</xsl:template> 

<xsl:template match="book"> 
    <xsl:variable name="cat" select="category"/> 
    <xsl:value-of select="category"/> : <xsl:text/> 
    <xsl:variable name="isbns" select="$vRef/reference/book[category=$cat]/@isbn"/> 
    <xsl:value-of select="count($meh/book[@isbn=$isbns])"/> 
    <xsl:text> book(s)&#xA;</xsl:text> 
</xsl:template> 
0

в оном к большому ответу Dimitri, я предлагаю следующее, чтобы не печатать категорию книг, которые имеют 0 книги установлена ​​в MyLibrary:

<xsl:variable name="catname" select="category"/> 
<xsl:for-each select="$vDoc"> 
    <xsl:variable name="cnt" select="count(key('kBookByIsbn',$vBooksinCat/@isbn))"/> 
    <xsl:if test="$cnt &gt; 0"> 
     <xsl:value-of select="$catname"/> : 
     <xsl:text/> 
     <xsl:value-of select="$cnt"/> 
     <xsl:text> book(s)&#xA;</xsl:text> 
    </xsl:if> 
</xsl:for-each>