2016-07-22 16 views
0

Ich möchte ein xml mit der folgenden Struktur zu transformierenXslt verteilen Listenelemente zu Knoten

<R> 
    <S> 
      <SN>S00</SN> 
      <SN>S01</SN> 
      <SN>S02</SN> 
    </S> 
    <L> 
     <ID>100</ID> 
     <Q>1</Q> 
    </L> 
    <L> 
     <ID>200</ID> 
     <Q>2</Q> 
    </L> 
</R> 

Um dies:

<R> 
    <L> 
     <ID>100</ID> 
     <Q>1</Q> 
     <S> 
      <SN>S00</SN> 
     </S> 
    </L> 
    <L> 
     <ID>200</ID> 
     <Q>2</Q> 
     <S> 
      <SN>S01</SN> 
      <SN>S02</SN> 
     </S>  
    </L> 
</R> 

Erläuterung: Die Aufgabe ist es, die Elemente des S-Element zu verteilen zu den L Elementen. Der Wert von Q in den jeweiligen L-Elementen steuert, wie viele Elemente von S in das L-Element verschoben werden sollen. Die Reihenfolge der S-Elemente spielt keine Rolle.

Denken Sie an einen praktischen Fall wie diesen: Es gibt eine Anzahl (Q) von Artikeln aus einer Produktionscharge (ID), und wir möchten jedem einzelnen Artikel eine Plakette mit einer Seriennummer (SN) anheften. Das Ergebnis der Umwandlung besagt: "Klebe die Plakette mit der Seriennummer S00 an die eine Position von Charge 100 und die Seriennummern S01 und S02 an die zwei Positionen von Charge 200 an."

+0

Willkommen in SO, @Bernhard! Was hast du probiert? Wo ist das Problem? Ihr Beitrag enthält keine Frage/Problem außer "Bitte tun Sie es für mich", was nicht SO ist ... also bitte bearbeiten Sie die Frage, um den problematischen Code anzuzeigen –

+0

Können Sie XSLT 2.0 verwenden? –

+0

Ich kann nur XSLT 1.0 verwenden – Bernhard

Antwort

0

Sie Geschwister Rekursion auf den L Elemente verwenden könnte, auf die Weitergabe restliche S elemente:

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

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

    <xsl:template match="R"> 
     <xsl:copy> 
      <xsl:variable name="sn" select="S/SN"/> 
      <xsl:apply-templates select="L[1]"> 
       <xsl:with-param name="sn" select="$sn"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="L"> 
     <xsl:param name="sn"/> 
     <xsl:copy> 
      <xsl:copy-of select="*"/> 
      <S> 
       <xsl:copy-of select="$sn[position() &lt;= current()/Q]"/> 
      </S> 
     </xsl:copy> 
     <xsl:apply-templates select="following-sibling::L[1]"> 
      <xsl:with-param name="sn" select="$sn[position() > current()/Q]"/> 
     </xsl:apply-templates> 
    </xsl:template> 

</xsl:stylesheet> 
+0

Das funktioniert sehr gut! – Bernhard

0

Interessantes Problem. Hier ist eine, wie man es aussehen könnte:

XSLT 1,0

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

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

<xsl:template match="Q"> 
    <xsl:variable name="start" select="sum(../preceding-sibling::L/Q)" /> 
    <xsl:variable name="end" select="$start + ." /> 
    <xsl:copy-of select="."/> 
    <S> 
     <xsl:copy-of select="../../S/SN[$start &lt; position() and position() &lt;= $end]"/> 
    </S> 
</xsl:template> 

<xsl:template match="S"/> 

</xsl:stylesheet> 

Das Problem bei diesem Ansatz, dass es nicht sehr effizient ist: jeder L Knoten berechnet die Summe von Q Werte aller vorhergehenden Geschwister statt einfach seinen Wert zu einer akkumulierten Summe hinzufügen.

Wenn Sie Ihre Eingabe eine große Anzahl von Knoten hat, einen rekursiven Ansatz betrachten - zum Beispiel:

XSLT 1,0

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

<xsl:template match="/R"> 
    <xsl:copy> 
     <xsl:call-template name="gen"> 
      <xsl:with-param name="batches" select="L"/> 
      <xsl:with-param name="labels" select="S/SN"/> 
     </xsl:call-template> 
    </xsl:copy> 
</xsl:template> 

<xsl:template name="gen"> 
    <xsl:param name="batches" select="/.."/> 
    <xsl:param name="labels" select="/.."/> 
    <xsl:variable name="batch" select="$batches[1]" /> 
    <xsl:variable name="q" select="$batch/Q" /> 
    <xsl:if test="$batches"> 
     <L> 
      <xsl:copy-of select="$batch/ID | $q"/> 
      <S> 
       <xsl:copy-of select="$labels[position() &lt;= $q]"/> 
      </S> 
     </L> 
     <!-- recursive call --> 
     <xsl:call-template name="gen"> 
      <xsl:with-param name="batches" select="$batches[position() > 1]"/> 
      <xsl:with-param name="labels" select="$labels[position() > $q]"/> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 
+0

Vielen Dank für Ihre Hilfe! Ich habe den rekursiven Ansatz berücksichtigt, aber ich konnte es noch nicht funktionieren. – Bernhard

+0

Funktioniert das obige nicht für Sie? –

+0

Beide Umwandlungen sind gut. Danke vielmals. – Bernhard