Michael: XML to CSV

Hallo,

ich bin gerade dabei eine XML in eine CSV-Liste Umzuwandeln. Meine Test XML hat folgende Struktur:

<POIliste>
  <POI Sprache="DEU">
    <Name>Frühstück</Name>
    <Preis></Preis>
    <Nr>1</Nr>
    <Typ>p</Typ>
  </POI>
  <POI>
    <Name>Mittagspause</Name>
    <Preis>1</Preis>
    <Nr>2</Nr>
    <Typ>p</Typ>
  </POI>
</POIliste>

Der CSV Header soll verschiedene Attribute und auch Elemente beinhalten. Hierführ habe ich eine Kombination aus einer Element- und Attributorientierten  XSLT entworfen. Diese sieht zur Zeit so aus:

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

<xsl:param name="Trenner" select="';'"/>
  <xsl:param name="Feld" select="''"/>
  <xsl:param name="Spaltenkoepfe" select="'TRUE'"/>
  <xsl:template match="/">
    <xsl:if test="$Spaltenkoepfe = 'TRUE'">

<!--Spaltenköpfe -->
      <xsl:for-each select="/*/*[1]/child::* | /*/*[1]/@*">
              <!-- Feldauszeichnung links -->
        <xsl:call-template name="Feldauszeichnung"/>
        <xsl:value-of select="local-name(.)"/>
        <!-- Feldauszeichnung rechts -->
        <xsl:call-template name="Feldauszeichnung"/>
        <!--Trenner -->
        <xsl:if test="not(position()=last())">
          <xsl:value-of select="$Trenner"/>
        </xsl:if>
      </xsl:for-each>
      xsl:text&#xD;</xsl:text>
    </xsl:if>

<!--Datenausgabe -->
    <xsl:for-each select="/*/*">
      <xsl:for-each select="child::* | @*">
        <!-- Feldauszeichnung links -->
        <xsl:call-template name="Feldauszeichnung"/>
        <xsl:value-of select="."/>
        <!-- Feldauszeichnung rechts -->
        <xsl:call-template name="Feldauszeichnung"/>
        <!--Trenner -->
        <xsl:if test="not(position()=last())">
          <xsl:value-of select="$Trenner"/>
        </xsl:if>
      </xsl:for-each>
      xsl:text&#xD;</xsl:text>
    </xsl:for-each>
  </xsl:template>

<!-- Feldauszeichnung -->
  <xsl:template name="Feldauszeichnung">
    <xsl:if test="$Feld != ''">
      <xsl:value-of select="$Feld"/>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

Als Ergebnis kommt nun folgendes heraus:

Sprache;Name;Preis;Nr;Typ
DEU;Frühstück;;1;p
Mittagspause;1;2;p

Das Problem ist nun, dass wenn das Element <POI> kein Attribut hat, nichts in der CSV Werteliste erscheint. In diesem Beispiel rutscht nun der Wert "Mittagspause" in die Zeile "Sprache".

Wie stricke ich mir nun eine Abfrage, die mir das ganze also richtig ausgibt:

Sprache;Name;Preis;Nr;Typ
DEU;Frühstück;;1;p
;Mittagspause;1;2;p

Vielen Dank schonmal für eure Hilfe!

Grüße,
Michael

  1. Hallo,

    xsl:choose verwendem?

    ohne die kopfzeile hier ein beispiel wie es gehen könnte

    <xsl:for-each select="//POI">
                xsl:choose
                    <xsl:when test="@Sprache">
                        <xsl:value-of select="@Sprache"/>
                        <!-- test if child exist -->
                        <xsl:if test="*">
                            <xsl:value-of select="$Trenner"/>
                        </xsl:if>
                    </xsl:when>
                    xsl:otherwise
                        <xsl:if test="*">
                            <xsl:value-of select="$Trenner"/>
                        </xsl:if>
                    </xsl:otherwise>
                </xsl:choose>
                <xsl:for-each select="*">
                    <xsl:value-of select="."/>
                    <xsl:if test="not(position() = last())">
                        <xsl:value-of select="$Trenner"/>
                    </xsl:if>
                </xsl:for-each>
            </xsl:for-each>

    1. Sorry,

      kann man auch nur mit xsl:if

      <xsl:for-each select="//POI">
                  <xsl:if test="@Sprache">
                          <xsl:value-of select="@Sprache"/>
                  </xsl:if>
                  <!-- test if child exist -->
                  <xsl:if test="*">
                        <xsl:value-of select="$Trenner"/>
                  </xsl:if>
                  <xsl:for-each select="*">
                      <xsl:value-of select="."/>
                      <xsl:if test="not(position() = last())">
                          <xsl:value-of select="$Trenner"/>
                      </xsl:if>
                  </xsl:for-each>
       </xsl:for-each>

      1. So, hab das mal wie folgt in die XSD eingbaut.

        Headerbereich fehlt!

        <!--Spaltenköpfe -->
              <xsl:for-each select="/*/*[1]/child::* | /*/*[1]/@*">
                      <!-- Feldauszeichnung links -->
                <xsl:call-template name="Feldauszeichnung"/>
                <xsl:value-of select="local-name(.)"/>
                <!-- Feldauszeichnung rechts -->
                <xsl:call-template name="Feldauszeichnung"/>
                <!--Trenner -->
                <xsl:if test="not(position()=last())">
                  <xsl:value-of select="$Trenner"/>
                </xsl:if>
              </xsl:for-each>
              xsl:text&#xD;</xsl:text>
            </xsl:if>

        <!-- Neue Datenausgabe -->
            <xsl:for-each select="//POI">
                    <xsl:if test="@Sprache">
                            <xsl:value-of select="@Sprache"/>
                    </xsl:if>
                    <!-- test if child exist -->
                    <xsl:if test="*">
                          <xsl:value-of select="$Trenner"/>
                    </xsl:if>
                    <xsl:for-each select="*">
                        <xsl:value-of select="."/>
                        <xsl:if test="not(position() = last())">
                            <xsl:value-of select="$Trenner"/>
                        </xsl:if>
                    </xsl:for-each>
            </xsl:for-each>

        </xsl:template>

        <!-- Feldauszeichnung -->
          <xsl:template name="Feldauszeichnung">
            <xsl:if test="$Feld != ''">
              <xsl:value-of select="$Feld"/>
            </xsl:if>
          </xsl:template>
        </xsl:stylesheet>

        Nun bekomme ich folgendes raus:

        Sprache;Name;Preis;Nr;Typ
        DEU;Frühstück;20;1;p;Mittagspause;1;2;p

        Anscheinend bekommt er es nun nicht hin, den neuen Eintrag in die nächste Spalte zu setzen. So wie hier:

        Sprache;Name;Preis;Nr;Typ
        DEU;Frühstück;20;1;p
        ;Mittagspause;1;2;p

        Wie könnte man das lösen?

        Danke übrigens für die schnelle Hilfe. Ist Gold wert!

        Sorry,

        kann man auch nur mit xsl:if

        <xsl:for-each select="//POI">
                    <xsl:if test="@Sprache">
                            <xsl:value-of select="@Sprache"/>
                    </xsl:if>
                    <!-- test if child exist -->
                    <xsl:if test="*">
                          <xsl:value-of select="$Trenner"/>
                    </xsl:if>
                    <xsl:for-each select="*">
                        <xsl:value-of select="."/>
                        <xsl:if test="not(position() = last())">
                            <xsl:value-of select="$Trenner"/>
                        </xsl:if>
                    </xsl:for-each>
        </xsl:for-each>

        1. Habs selbst hinbekommen ;)

          Es fehlte einfach:

          xsl:text&#xD;</xsl:text>
              </xsl:for-each>

          in der Anweisung. Die Anweisung lautet nun:

          <!-- Neue Datenausgabe -->
              <xsl:for-each select="//POI">
                      <xsl:if test="@Sprache">
                              <xsl:value-of select="@Sprache"/>
                      </xsl:if>
                      <!-- test if child exist -->
                      <xsl:if test="*">
                            <xsl:value-of select="$Trenner"/>
                      </xsl:if>
                      <xsl:for-each select="*">
                          <xsl:value-of select="."/>
                          <xsl:if test="not(position() = last())">
                              <xsl:value-of select="$Trenner"/>
                          </xsl:if>
                      </xsl:for-each>
                            xsl:text&#xD;</xsl:text>
              </xsl:for-each>
             </xsl:template>

          Danke!!!!

          So, hab das mal wie folgt in die XSD eingbaut.

          Headerbereich fehlt!

          <!--Spaltenköpfe -->
                <xsl:for-each select="/*/*[1]/child::* | /*/*[1]/@*">
                        <!-- Feldauszeichnung links -->
                  <xsl:call-template name="Feldauszeichnung"/>
                  <xsl:value-of select="local-name(.)"/>
                  <!-- Feldauszeichnung rechts -->
                  <xsl:call-template name="Feldauszeichnung"/>
                  <!--Trenner -->
                  <xsl:if test="not(position()=last())">
                    <xsl:value-of select="$Trenner"/>
                  </xsl:if>
                </xsl:for-each>
                xsl:text&#xD;</xsl:text>
              </xsl:if>

          <!-- Neue Datenausgabe -->
              <xsl:for-each select="//POI">
                      <xsl:if test="@Sprache">
                              <xsl:value-of select="@Sprache"/>
                      </xsl:if>
                      <!-- test if child exist -->
                      <xsl:if test="*">
                            <xsl:value-of select="$Trenner"/>
                      </xsl:if>
                      <xsl:for-each select="*">
                          <xsl:value-of select="."/>
                          <xsl:if test="not(position() = last())">
                              <xsl:value-of select="$Trenner"/>
                          </xsl:if>
                      </xsl:for-each>
              </xsl:for-each>

          </xsl:template>

          <!-- Feldauszeichnung -->
            <xsl:template name="Feldauszeichnung">
              <xsl:if test="$Feld != ''">
                <xsl:value-of select="$Feld"/>
              </xsl:if>
            </xsl:template>
          </xsl:stylesheet>

          Nun bekomme ich folgendes raus:

          Sprache;Name;Preis;Nr;Typ
          DEU;Frühstück;20;1;p;Mittagspause;1;2;p

          Anscheinend bekommt er es nun nicht hin, den neuen Eintrag in die nächste Spalte zu setzen. So wie hier:

          Sprache;Name;Preis;Nr;Typ
          DEU;Frühstück;20;1;p
          ;Mittagspause;1;2;p

          Wie könnte man das lösen?

          Danke übrigens für die schnelle Hilfe. Ist Gold wert!

          Sorry,

          kann man auch nur mit xsl:if

          <xsl:for-each select="//POI">
                      <xsl:if test="@Sprache">
                              <xsl:value-of select="@Sprache"/>
                      </xsl:if>
                      <!-- test if child exist -->
                      <xsl:if test="*">
                            <xsl:value-of select="$Trenner"/>
                      </xsl:if>
                      <xsl:for-each select="*">
                          <xsl:value-of select="."/>
                          <xsl:if test="not(position() = last())">
                              <xsl:value-of select="$Trenner"/>
                          </xsl:if>
                      </xsl:for-each>
          </xsl:for-each>