Mike Deuter: xml in eine ander xml konvertieren

Hallo,

ich wollte mal anfragen, ob jemand von euch mir einen tipp geben koennte. Und zwar muss ich ein xml dokument in ein anderes dokumnet umwandeln. dabei handelt es sich grob gesagt um dokumnete, die einen vergleichbaren aufbau wie xhtml usw. haben. das ganze läuft auch ganz gut, wenn es da nicht solche trick fälle geben würde. Im allgemein gehe ich so vor, dass ich stufenweise das dokument abarbeite mit xsl:apply-templates. Z.B:

<xsl:apply-template select="body"/>

<xsl:template match="body">
<body>
<xsl:apply-templtes select="nparag"/>
</body>
</xsl:template>

<xsl:template match="nparag">
...
</xsl:template>

ich muss nun nicht in xhtml umwandeln, aber in ein ähnliches format. Anbei ein beispiel, an dem ich langsam verzweifle. der obere teil stellt die xml quelle dar und der untere teil, wo ich hinkommen möchte. Allein mit apply-template scheine ich da nicht weiter zu kommen.

<nparag>this is a <ref> element</ref> text: <seqlist>
            <item>
                <para>listes parag. text</para>
            </item>
            <item>
                <para>listes parag. text</para>
            </item>
            <item>
                <para>listes parag. text</para>
            </item>
            <item>
                <para>listes parag. text<standard>another inbound element</standard>and the text goes on.</para>
            </item>
        </seqlist>
        <para>another text</para>
    </nparag>
    <!-- should be converted to -->
    text:pthis is a <refnew> element</refnew> text: </text:p>
    text:list
        text:list-item
            text:plistes parag. text</text:p>
        </text:list-item>
        text:list-item
            text:plistes parag. text</text:p>
        </text:list-item>
        text:list-item
            text:plistes parag. text</text:p>
        </text:list-item>
        text:list-item
            text:plistes parag. text<otherstandard>another inbound element</otherstandard>and the text goes on.</text:p>
        </text:list-item>
    </text:list>
    text:panother text</text:p>

  1. Hallo,

    ich wollte mal anfragen, ob jemand von euch mir einen tipp geben koennte. [...] Anbei ein beispiel, an dem ich langsam verzweifle. der obere teil stellt die xml quelle dar und der untere teil, wo ich hinkommen möchte. Allein mit apply-template scheine ich da nicht weiter zu kommen.

    <nparag>this is a <ref> element</ref> text: <seqlist>

    [...]

    </seqlist>
        </nparag>

    <!-- should be converted to -->
        text:pthis is a <refnew> element</refnew> text: </text:p>
        text:list
        </text:list>

    Sowas machen zu wollen ist ziemlich schlechter Stil / unüberlegter Dokumentdesing. Dementsprechend kannst du nur auf die übelste Art hacken (mit xsl:text), damit das geht:

    Grüße
    Thomas

    --------------------
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:text="http://example.org/text">
     <xsl:strip-space elements="*"/>
     <xsl:output method="xml" indent="yes"/>
     <xsl:template match="/">
      xsl:apply-templates/
     </xsl:template>

    <xsl:template match="nparag">
      xsl:apply-templates/
     </xsl:template>
     <xsl:template match="nparag/text()">
      <xsl:if test="not(preceding-sibling::text())">
       <xsl:text disable-output-escaping="yes">&lt;text:p&gt;</xsl:text>
      </xsl:if>
      xsl:copy
       xsl:apply-templates/
      </xsl:copy>
      <xsl:if test="not(following-sibling::text())">
       <xsl:text disable-output-escaping="yes">&lt;/text:p&gt;</xsl:text>
      </xsl:if>
     </xsl:template>
     <xsl:template match="ref">
      <newref>
       xsl:apply-templates/
      </newref>
     </xsl:template>
     <xsl:template match="seqlist">
      text:list
       xsl:apply-templates/
      </text:list>
     </xsl:template>
     <xsl:template match="item">
      text:list-item
       xsl:apply-templates/
      </text:list-item>
     </xsl:template>
     <xsl:template match="para">
      text:p
       xsl:apply-templates/
      </text:p>
     </xsl:template>
     <xsl:template match="standard">
      <otherstandard>
       xsl:apply-templates/
      </otherstandard>
     </xsl:template>
    </xsl:stylesheet>

    1. Hallo Thomas,

      ja das kannst du laut sagen, aber was soll ich machen,Seitenweise per Hand übersetzen? Die XSD Schemata sind vorgegeben. Und ich muss eben einen Weg finden, das automatisch generieren zu koennen. Habe ja nicht die XML Quelle entworfen. Werde mich gleich mal dran setzen, vielen Dank Dir.

      Gruß, Mike

    2. Hallo Thomas,

      die Codezeile funktionieren soweit ganz gut, nur taucht jetzt ein problem auf, wenn innerhalb eines knotens das eingeschlossenen element gleich am Anfang erscheint und dann noch weitere "eingeschlossenen" Elemente folgen. Ich frga mich selber gerade, wie man einen Textknoten mit eingeschlossenen Unterknoten verarbeiten kann. Wie du vielleicht erkennen kannst, soll die transformation in ein odt Dokument erfolgen und die XML quelle liegt mir nur so vor. Aber selbst bei Open-Office sind die eingeschlossenen Elemente in einem Textknoten anzutreffen. Zudem hat mich das disable-output schon eine kleine muehe gekostet in meinem cocoon, da es standardmäßig nicht unterstützt wird. Wenn ich nun noch attribute an das text:p element hängen moechte wird es ganz "hackig". Wenn dir noch etwas einfällt zu der unten angegeben konvertierung, wuerde ich mich freuen, ansonsten trotzdem vielen Dnak, hat mir weitergeholfen und werde noch mal in ruhe darüber anchdenken.

      Viele Grüße,
      Mike

      <nparag>text zeile:
              <para>
                  <definition>defintionstext</definition>
                  weiter im paragraph.
              </para>
              <para>
                  <definition>noch eine definition</definition>
                  weiter im text:
              </para>
              <seqlist>
                  <item>
                      <para>aufzaehlungstext;</para>
                  </item>
                  <item>
                      <para>weitere aufzaehlungen</para>
                  </item>
                  <item>
                      <para>und noch eine aufzaehlung.</para>
                  </item>
              </seqlist>
              <para>
                  <definition>wieder eine definition</definition>
                  weiter im
                  <ref>text</ref>
                  der zu para gehoert
              </para>
          </nparag>
          <!--- soll zu -->
          text:ptext zeile: </text:p>
              text:p
                  <definition>defintionstext</definition>
                  weiter im paragraph.
              </text:p>
              text:p
                  <definition>noch eine definition</definition>
                  weiter im text:
              </text:p>
                text:list
                  text:list-item
                      text:paufzaehlungstext;</text:p>
                  </text:list-item>
                  text:list-item
                      text:pweitere aufzaehlungen</text:p>
                  </text:list-item>
                  text:list-item
                      text:pund noch eine aufzaehlung.</text:p>
                  </text:list-item>
             </text:list>
              text:p
                  <definition>wieder eine definition</definition>
                  weiter im
                  <ref>text</ref>
                  der zu para gehoert
              </text:p>

      1. Hallo,

        die Codezeile funktionieren soweit ganz gut, nur taucht jetzt ein problem auf, wenn innerhalb eines knotens das eingeschlossenen element gleich am Anfang erscheint und dann noch weitere "eingeschlossenen" Elemente folgen. Ich frga mich selber gerade, wie man einen Textknoten mit eingeschlossenen Unterknoten verarbeiten kann. Wie du vielleicht erkennen kannst, soll die transformation in ein odt Dokument erfolgen und die XML quelle liegt mir nur so vor. Aber selbst bei Open-Office sind die eingeschlossenen Elemente in einem Textknoten anzutreffen. Zudem hat mich das disable-output schon eine kleine muehe gekostet in meinem cocoon, da es standardmäßig nicht unterstützt wird. Wenn ich nun noch attribute an das text:p element hängen moechte wird es ganz "hackig". Wenn dir noch etwas einfällt zu der unten angegeben konvertierung, wuerde ich mich freuen, ansonsten trotzdem vielen Dnak, hat mir weitergeholfen und werde noch mal in ruhe darüber anchdenken.

        Wenn ich das XSL, was ich vorher postete auf dein XML anwende:

        <!--- soll zu -->
            text:ptext zeile: </text:p>
                text:p
                    <definition>defintionstext</definition>
                    weiter im paragraph.
                </text:p>
                text:p
                    <definition>noch eine definition</definition>
                    weiter im text:
                </text:p>
                  text:list
                    text:list-item
                        text:paufzaehlungstext;</text:p>
                    </text:list-item>
                    text:list-item
                        text:pweitere aufzaehlungen</text:p>
                    </text:list-item>
                    text:list-item
                        text:pund noch eine aufzaehlung.</text:p>
                    </text:list-item>
               </text:list>
                text:p
                    <definition>wieder eine definition</definition>
                    weiter im
                    <ref>text</ref>
                    der zu para gehoert
                </text:p>

        bekomme ich als Ausgabe (jetzt mal nicht die Namesräume beachten) egal ob mit Saxon oder Xalan:
        -------------------------
        text:ptext zeile: </text:p>
         <text:p xmlns:text="http://example.org/text">
          <definition>defintionstext</definition> weiter im paragraph. </text:p>
         <text:p xmlns:text="http://example.org/text">
          <definition>noch eine definition</definition> weiter im text: </text:p>
         <text:list xmlns:text="http://example.org/text">
          text:list-item
           text:paufzaehlungstext;</text:p>

        </text:list-item>
          text:list-item
           text:pweitere aufzaehlungen</text:p>
          </text:list-item>
          text:list-item
           text:pund noch eine aufzaehlung.</text:p>
          </text:list-item>
         </text:list>

        <text:p xmlns:text="http://example.org/text">
          <definition>wieder eine definition</definition> weiter im <newref>text</newref> der zu para gehoert </text:p>
        ------------------------

        was ziemlich genau dein Zielformat entspricht.
        Das mit disable-output vestehe ich nicht ganz, Coocon verwendet doch Xalan und der kann XSLT 1.0 ganz normal.
        Wenn du Attribute brauchst muss du diese wohl oder übel selbst im Element (das im xsl:text steht) kodieren.

        Grüße
        Thomas

        1. Hallo Thomas,

          hm, bei mir hatte es nicht funktioniert. Muss ich noch mal schauen, habe jetzt aber auch noch einen Weg gefunden. Da nach </para></nparag> folgt und keine weitere Text mehr dazwischen enthalten ist. kann ich apply templates innerhalb von text:p element einauen und entsprechende elemente auschliessen um diese dann nach dem text:p element noch einmal gesondert aufzurufen, funktioniert soweit ganz gut.

          Zu dem disable-output muss ich sagen, dass ich die die letzte stable Cocoon 2.1.10 benutze und mir dort hinein noch den saxon8 integriert habe. Man muss dann noch die transform-factory auf xalan setzen, weil ansosnten wohl jaxp arbeitet. Gut nachzulesen hier: http://blog.reverycodes.com/archives/000034.html

          Gruß,
          M.

          1. Hallo,

            [...] habe jetzt aber auch noch einen Weg gefunden funktioniert soweit ganz gut.

            Hmmm ....

            Zu dem disable-output muss ich sagen, dass ich die die letzte stable Cocoon 2.1.10 benutze und mir dort hinein noch den saxon8 integriert habe.

            Da wäre vielleicht eine Überlegung Wert, ob du dich mit XSLT 2.0 beschäftigst (wenn du schon Saxon 8.x hast)?

            Man muss dann noch die transform-factory auf xalan setzen, weil ansosnten wohl jaxp arbeitet. Gut nachzulesen hier: http://blog.reverycodes.com/archives/000034.html

            *sigh* ich dachte, sie hättes das schon behoben ... *pfffff*

            Grüße
            Thomas