2017-08-31 1 views
0

Ich verwende eine XSLT-Transformation, um ein XML-Dokument zu erzeugen, das nach der Erstellung geteilt wird, um mehrere Dateien zu erzeugen. Die allgemeine Struktur des endgültigen Dokuments ist etwa so:XSLT 1.0 - Anzahl der Datensätze pro Datei begrenzen

<DOC> 
    <NEWFILE/> 
    <REALROOT> 
     <SENDER></SENDER> 
     <INVOICE> 
      <IVC_ID></IVS_ID> 
      <LINEITEM></LINEITEM> 
      <LINEITEM></LINEITEM> 
      ... 
     </INVOICE> 
     <INVOICE> 
      <IVC_ID></IVS_ID> 
      <LINEITEM></LINEITEM> 
      <LINEITEM></LINEITEM> 
      ... 
     </INVOICE> 
     ... 
    </REALROOT> 

    <NEWFILE/> 

    <REALROOT> 
     <SENDER></SENDER> 
     <INVOICE> 
      <IVC_ID></IVS_ID> 
      <LINEITEM></LINEITEM> 
      <LINEITEM></LINEITEM> 
      ... 
     </INVOICE> 
     <INVOICE> 
      <IVC_ID></IVS_ID> 
      <LINEITEM></LINEITEM> 
      <LINEITEM></LINEITEM> 
      ... 
     </INVOICE> 
     ... 
    </REALROOT> 
    <NEWFILE/> 
</DOC> 

Die DOC und <NEWFILE/> Tags die Grenzen des Endproduktes sind, aber das ist nicht das Thema der Frage.

Meine Eingabedaten müssen nach Absender und Rechnung gruppiert werden, bevor sie an die obige Struktur ausgegeben werden, und ich habe es geschafft, aber ich möchte auch die Anzahl der Rechnungen pro Datei begrenzen und nicht in der Lage sein finde einen Weg, das zu tun.

ist Meine Eingangsdaten in die Positionsebene wie so aufgeschlüsselt:

<ROOT> 
    <DATA> 
     <SNDR>1</SNDR> 
     <INVOICE>1</INVOICE> 
     <LINEITEM>1</LINEITEM> 
    </DATA> 
    <DATA> 
     <SNDR>1</SNDR> 
     <INVOICE>1</INVOICE> 
     <LINEITEM>2</LINEITEM> 
    </DATA> 
    <DATA> 
     <SNDR>1</SNDR> 
     <INVOICE>2</INVOICE> 
     <LINEITEM>1</LINEITEM> 
    </DATA> 
    <DATA> 
     <SNDR>1</SNDR> 
     <INVOICE>3</INVOICE> 
     <LINEITEM>1</LINEITEM> 
    </DATA> 
    <DATA> 
     <SNDR>1</SNDR> 
     <INVOICE>3</INVOICE> 
     <LINEITEM>2</LINEITEM> 
    </DATA> 
    <DATA> 
     <SNDR>2</SNDR> 
     <INVOICE>1</INVOICE> 
     <LINEITEM>1</LINEITEM> 
    </DATA> 
    <DATA> 
     <SNDR>2</SNDR> 
     <INVOICE>2</INVOICE> 
     <LINEITEM>1</LINEITEM> 
    </DATA> 
</ROOT> 

Wenn ich es begrenzen pro Datei zu 2 Rechnungen, würde ich diese Ausgabe erwarten:

<DOC> 
    <REALROOT> 
     <SENDER>1</SENDER> 
     <INVOICE> 
      <IVC_ID>1</IVS_ID> 
      <LINEITEM>1</LINEITEM> 
      <LINEITEM>2</LINEITEM> 
     </INVOICE> 
     <INVOICE> 
      <IVC_ID>2</IVS_ID> 
      <LINEITEM>1</LINEITEM> 
     </INVOICE> 
    </REALROOT> 

    <NEWFILE/> 

    <REALROOT> 
     <SENDER>1</SENDER> 
     <INVOICE> 
      <IVC_ID>3</IVS_ID> 
      <LINEITEM>1</LINEITEM> 
      <LINEITEM>2</LINEITEM> 
     </INVOICE> 
    </REALROOT> 

    <NEWFILE/> 

    <REALROOT> 
     <SENDER>2</SENDER> 
     <INVOICE> 
      <IVC_ID>1</IVS_ID> 
      <LINEITEM>1</LINEITEM> 
     </INVOICE> 
     <INVOICE> 
      <IVC_ID>2</IVS_ID> 
      <LINEITEM>1</LINEITEM> 
     </INVOICE> 
    </REALROOT> 
</DOC> 

Hier was ich zu weit habe. Dies erlaubt mir, die Zeilen nach Absender und Rechnung zu gruppieren, aber ich kann nicht herausfinden, wie ich in der Anzahl der Rechnungen arbeiten soll.

+0

Sie können nicht etwas gruppieren, das noch nicht existiert. Sie müssen dies in zwei Schritten tun: Zuerst gruppieren Sie die Artikel in Rechnungen, dann gruppieren Sie Rechnungen in Dateien. –

+0

XSLT ist Turing-vollständig. Wenn Sie eine Ausgabe mit einer Programmiersprache erstellen können, können Sie sie mit XSLT erzeugen. Ob es vernünftig ist zu versuchen, ist eine andere Frage. – kumesana

Antwort

0

Zuerst benötigen Sie für jeden Absender eine Liste aller Rechnungen für diesen Absender.

Das ist schon was du mit deinen ersten beiden foreach machst, aber ich sagte, du brauchst eine Liste. Die zweite muss also keine foreach sein. Legen Sie diese in einer Variablen statt:

<xsl:variable name="invoicesWithThisSender" 
        select="key('data-by-SNDR', current()/SNDR)[not(INVOICE = preceding-sibling::DATA[1]/INVOICE)]" /> 

Es ist die gleiche Auswahl, in einer Variablen anstelle von for-each.

Jetzt müssen Sie alle Elemente dieser Liste in so viele Dateien schreiben, wie nötig.

Da XSLT 1.0 keine Partitionsmechanismen bietet, kann ich nur eine rekursive benannte Vorlage aufrufen.

Try this:

<xsl:template name="writeFilesForSender"> 
    <xsl:param name="invoicesWithThisSender" /> 

    <xsl:if test="$invoicesWithThisSender"> 
     <NEWFILE /> 

     <REALROOT> 
      <SNDR> 
       <xsl:value-of select="SNDR" /> 
      </SNDR> 
      <xsl:for-each select="$invoicesWithThisSender[position() &lt;= 2]"> 
       <INVOICE> 
        <IVC_ID> 
         <xsl:value-of select="INVOICE" /> 
        </IVC_ID> 
       </INVOICE> 
      </xsl:for-each> 
     </REALROOT> 

     <xsl:call-template name="writeFilesForSender"> 
      <xsl:with-param name="invoicesWithThisSender" 
       select="$invoicesWithThisSender[position() > 2]" /> 
     </xsl:call-template> 
    </xsl:if> 

</xsl:template> 

nennen es mit diesem:

<xsl:call-template name="writeFilesForSender"> 
    <xsl:with-param name="invoicesWithThisSender" 
     select="$invoicesWithThisSender" /> 
</xsl:call-template> 

Von dem, was ich verstehe und meine Tests, Ihr Problem gelöst ist.

+0

https://stackoverflow.com/questions/45968516/simple-xsl-issue-with-if-statement-inside-for-each/45968983#45968983 –

+0

@ michael.hor257k Ja, viel besser. Ich denke, es ist eine eigene Antwort wert. – kumesana

Verwandte Themen