2012-10-08 10 views
5

Muenchian grouping nasıl çalışır?XSLT ile basit bir XML için Muenchian gruplaması uygulama

<CLIENTS> 
    <CLIENT> 
     <NAME>John</NAME> 
     <ACCOUNT_NUMBER>1424763562761</ACCOUNT_NUMBER> 
     <LAST_USED>2012-10-03</LAST_USED> 
     <AMOUNT>5000</AMOUNT> 

    </CLIENT> 
    <CLIENT> 
     <NAME>John</NAME> 
     <ACCOUNT_NUMBER>543667543732</ACCOUNT_NUMBER> 
     <LAST_USED>2012-10-02</LAST_USED> 
     <AMOUNT>10000</AMOUNT> 
    </CLIENT> 
     ... 

de ismi düğüm tarafından grup istiyorum:

Bir veritabanından oluşturulan basit bir XML belgesi var. İstenilen çıkış aşağıdaki gibi nasıl olabilir?

<ClIENTS> 
    <CLIENT> 
     <NAME>John</NAME> 
     <ACCOUNT> 
      <ACCOUNT_NUMBER>1424763562761</ACCOUNT_NUMBER> 
      <LAST_USED>2012-10-03</LAST_USED> 
      <AMOUNT>5000</AMOUNT> 
     </ACCOUNT> 
     <ACCOUNT> 
      <ACCOUNT_NUMBER>543667543732</ACCOUNT_NUMBER> 
      <LAST_USED>2012-10-03</LAST_USED> 
      <AMOUNT>10000</AMOUNT> 
     </ACCOUNT> 
     .... 
</CLIENTS> 

cevap

8

Oku www.jenitennison.com/xslt/grouping/muenchian.xml, koduyla bir yardım daha sonra XSLT 2.0 kullanmak istiyorsanız anahtar

<xsl:key name="client-by-name" match="CLIENT" use="NAME"/> 

sonra

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


<xsl:template match="CLIENTS"> 
    <xsl:copy> 
    <xsl:apply-templates select="CLIENT[generate-id() = generate-id(key('client-by-name', NAME)[1])]" mode="group"/> 
    <xsl:copy> 
</xsl:template> 

<xsl:template match="CLIENT" mode="group"> 
    <xsl:copy> 
    <xsl:copy-of select="NAME"/> 
    <xsl:apply-templates select="key('client-by-name', NAME)"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="CLIENT"> 
    <ACCOUNT> 
    <xsl:apply-templates select="node()[not(self::NAME)]"/> 
    </ACCOUNT> 
</xsl:template> 

[değiştir] olarak şablonları kullanmak tanımlamak için Tabii ki Muenchian gruplandırmasına ihtiyacınız yok, bunun yerine

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

<xsl:template match="CLIENTS"> 
    <xsl:copy> 
    <xsl:for-each-group select="CLIENT" group-by="NAME"> 
     <CLIENT> 
     <xsl:apply-templates select="NAME, current-group()"/> 
     </CLIENT> 
    </xsl:for-each-group> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="CLIENT"> 
    <ACCOUNT> 
    <xsl:apply-templates select="node() except NAME"/> 
    </ACCOUNT> 
</xsl:template> 
+0

Çok yararlı cevaplar çocuklar için teşekkürler. Aynı sorunu xslt 2.0 xls ile çözmek mümkün mü: her grup için? Varsa, lütfen çözümü gönderir misiniz? – user1728778

+0

@ user1728778 - Evet, bu mümkün. Kompakt bir XSLT 2.0 çözümü için lütfen cevabıma bakın. Muenchian Grouping'in neden gerekli olduğunu açıklayan – ABach

4

Jeni Tennison burada Muenchian gruplama gerçekleştirmek için gereken adımları kırar:

Esasen

http://www.jenitennison.com/xslt/grouping/muenchian.html

, düğüme bir anahtar atamak için XSLT kullanabilirsiniz, bu anahtar belgede özdeş düğümleri varsa tekrarlanabilir. XSLT daha sonra her bir tuştan geçer ve düğümleri eşleşen anahtarlarla çıkarmanızı sağlar.

Yani, Martin'in yanıtında, bu hat ADI düğümün içeriğini temel alarak her MÜŞTERİ için bir anahtar yaratıyor (anahtar ADI birden çok müşteri için aynıysa hatırlamak, bu yüzden olacak):

<xsl:key name="client-by-name" match="CLIENT" use="NAME"/> 

ardından ardından çıktı edebilmek için kilit maç MÜŞTERİLER tüm bulmak istiyoruz

<xsl:apply-templates select="CLIENT[generate-id() = generate-id(key('client-by-name', NAME)[1])]" mode="group"/> 

tüm tuşları geçmesi ve (yine Martin'in cevabı kullanılarak) her birinin birinci örneğini bulmak istiyorum onların detay (tekrar, Martins)

<xsl:apply-templates select="key('client-by-name', NAME)"/> 

Buradan MÜŞTERİ ayrıntıları

3

Muenchian Gruplamasını (Martin'in cevabı @ uyarınca) çıkışına başka bir şablon gerek daha geleneksel gruplama stratejisi gruplama iken sahip olduğu fazlalık ortadan kaldırır ederim.

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

    <xsl:template match="CLIENTS"> 
     <CLIENTS> 
      <!--Only find the 'first' instance of each client--> 
      <xsl:apply-templates select="CLIENT[not(NAME = preceding-sibling::CLIENT/NAME)]" mode="client"/> 
     </CLIENTS> 
    </xsl:template> 

    <xsl:template match="CLIENT" mode="client"> 
     <xsl:variable name="name" select="NAME"/> 
     <CLIENT> 
      <NAME> 
       <xsl:value-of select="$name"/> 
      </NAME> 
      <ACCOUNTS> 
       <!--Note that we now have to find the other matching clients *again* - this is the inefficiency that Muenchian grouping eliminates--> 
       <xsl:apply-templates select="/CLIENTS/CLIENT[NAME/text()=$name]" mode="account" /> 
      </ACCOUNTS> 
     </CLIENT> 
    </xsl:template> 

    <xsl:template match="CLIENT" mode="account"> 
     <ACCOUNT> 
      <!--Copy everything else except Name, which is the grouping key --> 
      <xsl:copy-of select="@* | *[not(local-name='NAME')]"/> 
     </ACCOUNT> 
    </xsl:template> 

</xsl:stylesheet> 
+2

+1. – ABach

1

olarak aşağıdaki gibidir:

Muenchian Gruplama olmadan, şablonlar, genellikle grubuna uygun tüm düğümleri arama için ikinci bir sorgu gerektirecektir daha sonra her grubun birinci aday örneği belirlemek için preceding-sibling veya following-sibling kullanılabilir ve Önceki bir yorum (@ Martin'in cevabı altında), OP bu sorunu çözmek için XSLT 2.0'ın for-each-group öğesinin kullanılabileceğini sordu.

Bu XSLT 2 olduğunda.0 çözüm:

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

    <xsl:template match="/*"> 
    <CLIENTS> 
     <xsl:for-each-group select="CLIENT" group-by="NAME"> 
     <CLIENT> 
      <xsl:sequence select="NAME" /> 
      <xsl:for-each select="current-group()"> 
      <ACCOUNT> 
       <xsl:sequence select="*[not(self::NAME)]" /> 
      </ACCOUNT> 
      </xsl:for-each> 
     </CLIENT> 
     </xsl:for-each-group> 
    </CLIENTS> 
    </xsl:template> 

</xsl:stylesheet> 

... OP'ın orijinal XML uygulanır:

<CLIENTS> 
    <CLIENT> 
    <NAME>John</NAME> 
    <ACCOUNT_NUMBER>1424763562761</ACCOUNT_NUMBER> 
    <LAST_USED>2012-10-03</LAST_USED> 
    <AMOUNT>5000</AMOUNT> 
    </CLIENT> 
    <CLIENT> 
    <NAME>John</NAME> 
    <ACCOUNT_NUMBER>543667543732</ACCOUNT_NUMBER> 
    <LAST_USED>2012-10-02</LAST_USED> 
    <AMOUNT>10000</AMOUNT> 
    </CLIENT> 
</CLIENTS> 

... istenilen sonucu üretilen:

<?xml version="1.0" encoding="utf-8"?> 
<CLIENTS> 
    <CLIENT> 
    <NAME>John</NAME> 
    <ACCOUNT> 
     <ACCOUNT_NUMBER>1424763562761</ACCOUNT_NUMBER> 
     <LAST_USED>2012-10-03</LAST_USED> 
     <AMOUNT>5000</AMOUNT> 
    </ACCOUNT> 
    <ACCOUNT> 
     <ACCOUNT_NUMBER>543667543732</ACCOUNT_NUMBER> 
     <LAST_USED>2012-10-02</LAST_USED> 
     <AMOUNT>10000</AMOUNT> 
    </ACCOUNT> 
    </CLIENT> 
</CLIENTS> 

Açıklama:

Zaten doğru bir şekilde tahmin ettiğiniz gibi, XSLT 2.0, Muenchian Metodu gibi şaşırtıcı/etkileyici, ancak potansiyel olarak kafa karıştırıcı gruplama metodolojilerini ortadan kaldırmak içinöğesini (ve current-group() gibi ilişkili ortaklarını) tanıttı.