Pasujące szablony o różnej konfiguracji w tym samym węźle

Nov 23 2020

Zadałem tutaj całe moje pytanie dotyczące przepełnienia stosu , spróbuję je pokroić:

Muszę utworzyć xml z tego źródła: bardzo krótko:

    <?xml version="1.0" encoding="UTF-8"?>
    <FMPDSORESULT xmlns="http://www.filemaker.com/fmpdsoresult">
        <ROW>
        <EDI_DC40.TABNAM><DATA>EDI_DC40</DATA></EDI_DC40.TABNAM>
        <E1EDL20.VBELN><DATA>649758</DATA></E1EDL20.VBELN>
        <E1EDL18.QUALF><DATA>ORI</DATA></E1EDL18.QUALF>
        <E1EDT13.1.QUALF><DATA>007<DATA></E1EDT13.1.QUALF>
        <E1EDT13.2.QUALF><DATA>015</DATA></E1EDT13.2.QUALF>
        <E1EDL24.POSNR>000001</E1EDL24.POSNR>
        <E1EDL24.POSNR>2</E1EDL24.POSNR>
                (random number of these)
        <E1EDL41.QUALI>001</E1EDL41.QUALI>
        <E1EDL37.EXIDV><DATA>5650327422</DATA></E1EDL37.EXIDV>
        <E1EDL44.POSNR>000001</E1EDL44.POSNR> <!--(these are the line items, equal to the number of ROW)-->
    </ROW>
    <ROW>...

To jest to, czego potrzebuję:

    <DELVRY05>
        <IDOC BEGIN="1">
            <EDI_DC40 SEGMENT="1">
                <TABNAM>EDI-DC40</TABNAM>
            </EDI_DC40>
            <E1EDL20 SEGMENT="1">
                <VBELN>649758</VBELN>
                <E1EDL18 SEGMENT="1"><QUALF>ORI</QUALF></E1EDL18>
                <E1EDT13 SEGMENT="1"><QUALF>007</QUALF></E1EDT13>
                <E1EDT13 SEGMENT="1"><QUALF>015</QUALF></E1EDT13>
                <E1EDL24 SEGMENT="1">
                    <POSNR>000001</POSNR>
                    <E1EDL41 SEGMENT="1">
                        <QUALI>001</QUALI>
                    </E1EDL41>
                </E1EDL24>
                <E1EDL24 SEGMENT="1">
                    <POSNR>2</POSNR>
                    <E1EDL41 SEGMENT="1">
                         <QUALI>001</QUALI>
                    </E1EDL41>
                </E1EDL24>
                <E1EDL24 SEGMENT="1"> <!-- (random number of these, as commented above) -->
                    ...
                </E1EDL24>
            </E1EDL20>
        </IDOC>
    </DELVRY05>

Oto pomysł na xsl:

    <xsl:template match="/*">
        <DELVRY05>
            <IDOC BEGIN="1">
                <EDI_DC40 SEGMENT="1">
                    <xsl:apply-templates select="headers"/>
                </EDI_DC40>
                <E1EDL20 SEGMENT="1">
                    <xsl:apply-templates select="main"/>
                    <xsl:apply-templates select="fm:ROW"/>
                </E1EDL20>
            </IDOC>
        </DELVRY05>
    </xsl:template>

Ponieważ zarówno wiersze, jak i nagłówki są zawarte w tagu E1EDL20, widzę potrzebę dwóch szablonów i oba odnoszą się do tego samego tagu w kodzie źródłowym. Jak mówią specyfikacje, używany jest tylko ostatni szablon. (więc zobaczy „nagłówek” i „linie”, ale nie „główne”:

    <xsl:template name="main" match="fm:ROW[1]"> ...

    <xsl:template name="headers" match="fm:ROW[1]"> ...

    <xsl:template name="lines" match="fm:ROW"> ...

Jak to rozwiązać?

Edytować:

@Sebastien: Twoje rozwiązanie działało świetnie w przypadku kodu źródłowego, który dostarczyłem na początku. Doskonała odpowiedź. Zrobiłem jednak błąd w podanym kodzie, przepraszam.

Oto format kodu źródłowego:

    <?xml version="1.0" encoding="UTF-8"?>
    <FMPDSORESULT xmlns="http://www.filemaker.com/fmpdsoresult">
        <ROW>
            <EDI_DC40.TABNAM><DATA>EDI_DC40</DATA></EDI_DC40.TABNAM>
            <E1EDL20.VBELN><DATA>649758</DATA></E1EDL20.VBELN>
            <E1EDL18.QUALF><DATA>ORI</DATA></E1EDL18.QUALF>
            <E1EDT13.1.QUALF><DATA>007</DATA></E1EDT13.1.QUALF>
            <E1EDT13.2.QUALF><DATA>015</DATA></E1EDT13.2.QUALF>
            <E1EDL24.POSNR>000001</E1EDL24.POSNR>
            <E1EDL41.QUALI>001</E1EDL41.QUALI>
            <E1EDL37.EXIDV><DATA>5650327422</DATA></E1EDL37.EXIDV>
            <E1EDL44.POSNR>000001</E1EDL44.POSNR>
        </ROW>
        <ROW>
            <EDI_DC40.TABNAM><DATA>EDI_DC40</DATA></EDI_DC40.TABNAM>
            <E1EDL20.VBELN><DATA>649758</DATA></E1EDL20.VBELN>
            <E1EDL18.QUALF><DATA>ORI</DATA></E1EDL18.QUALF>
            <E1EDT13.1.QUALF><DATA>007</DATA></E1EDT13.1.QUALF>
            <E1EDT13.2.QUALF><DATA>015</DATA></E1EDT13.2.QUALF>
            <E1EDL24.POSNR>2</E1EDL24.POSNR>
            <E1EDL41.QUALI>002</E1EDL41.QUALI>
            <E1EDL37.EXIDV><DATA>5650327422</DATA></E1EDL37.EXIDV>
            <E1EDL44.POSNR>000001</E1EDL44.POSNR>
        </ROW>
    </FMPDSORESULT>

Wyzwanie polega na tym, że powinienem mieć jeden tag z nagłówkami, ale elementy zamówienia powinny być wymienione jeden pod drugim, na przykład:

    <?xml version="1.0" encoding="utf-16"?>
    <DELVRY05>
      <IDOC BEGIN="1">
        <EDI_DC40 SEGMENT="1">
          <TABNAM>EDI_DC40</TABNAM>
        </EDI_DC40>
        <E1EDL20 SEGMENT="1">
          <VBELN>649758</VBELN>
          <E1EDL18 SEGMENT="1">
            <QUALF>ORI</QUALF>
          </E1EDL18>
          <E1EDL24 SEGMENT="1">
            <POSNR>000001</POSNR>
            <E1EDL41 SEGMENT="1">
              <QUALI>001</QUALI>
            </E1EDL41>
          </E1EDL24>
          <E1EDL24 SEGMENT="1">
            <POSNR>2</POSNR>
            <E1EDL41 SEGMENT="1">
              <QUALI>002</QUALI>
            </E1EDL41>
          </E1EDL24>
        </E1EDL20>
      </IDOC>
    </DELVRY05>

Dziękuję za wyrozumiałość. Ogromnie doceniam twoją pomoc!

Jestem bardzo zobowiązany, Tom

Odpowiedzi

Sebastien Nov 23 2020 at 16:38

Oto próbka na początek. W twoim pytaniu brakuje niektórych szczegółów, niektóre przyjąłem pewne zasady.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fm="http://www.filemaker.com/fmpdsoresult"
    exclude-result-prefixes="fm"
    version="1.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <DELVRY05>
      <xsl:apply-templates select="fm:FMPDSORESULT/fm:ROW[1]"/>
    </DELVRY05>
  </xsl:template>
  
  <xsl:template match="fm:ROW">
    <IDOC BEGIN="1">
      <EDI_DC40 SEGMENT="1">
        <TABNAM><xsl:value-of select="fm:EDI_DC40.TABNAM/fm:DATA"/></TABNAM>
      </EDI_DC40>
      <E1EDL20 SEGMENT="1">
        <VBELN><xsl:value-of select="fm:E1EDL20.VBELN/fm:DATA"/></VBELN>
        <E1EDL18 SEGMENT="1"><QUALF><xsl:value-of select="fm:E1EDL18.QUALF/fm:DATA"/></QUALF></E1EDL18>
        <!-- Same principle as above for E1EDT13.1, E1EDT1.2, etc. -->
        
        <!-- Use template for elements that are present mutltiple times. -->
        <xsl:apply-templates select="../fm:ROW/fm:E1EDL24.POSNR"/>
      </E1EDL20>
    </IDOC>
  </xsl:template>
  
  <xsl:template match="fm:E1EDL24.POSNR">
    <E1EDL24 SEGMENT="1">
      <POSNR><xsl:value-of select="."/></POSNR>
      <E1EDL41 SEGMENT="1">
        <QUALI><xsl:value-of select="../fm:E1EDL41.QUALI"/></QUALI>
      </E1EDL41>
    </E1EDL24>
  </xsl:template>
  
</xsl:stylesheet>

Zobacz, jak działa tutaj: https://xsltfiddle.liberty-development.net/6q1SDka/1