Announcement

Collapse
No announcement yet.

Zusammenfassen nach ID

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Zusammenfassen nach ID

    Hallo zusammen,

    ich versuche mit XSLT eine XML-Datei in ein anderes Format zu bringen. Die Ausgangsdatei hat folgendes aussehen:

    Code:
    <csvimport>
    <row>
    <Begriffsid>100</Begriffsid>
    <Benennung>Emil</Benennung>
    <Status>vater</Status>
    </row>
    <row>
    <Begriffsid>101</Begriffsid>
    <Benennung>Max</Benennung>
    <Status>vater</Status>
    </row>
    <row>
    <Begriffsid>100</Begriffsid>
    <Benennung>Frank</Benennung>
    <Status>sohn</Status>
    </row>
    <row>
    <Begriffsid>100</Begriffsid>
    <Benennung>Martin</Benennung>
    <Status>sohn</Status>
    </row>
    <row>
    <Begriffsid>101</Begriffsid>
    <Benennung>Thomas</Benennung>
    <Status>sohn</Status>
    </row>
    <row>
    <Begriffsid>101</Begriffsid>
    <Benennung>Anke</Benennung>
    <Status>tochter</Status>
    </row>
    </csvimport>
    Und so soll sie später aussehen:

    Code:
    <documents>
    <document>
    <Begriffsid>100</Begriffsid>
    <Benennung>Emil</Benennung>
    <kinder>Frank, Martin</kinder>
    </document>
    <document>
    <Begriffsid>101</Begriffsid>
    <Benennung>Emil</Benennung>
    <kinder>Thomas, Anke</kinder>
    </document>
    </documents>
    Eigentlich nicht schwer, dachte ich. Aber vielleicht ist mein Ansatz auch falsch. Auszug aus meinem Code:
    Code:
    <xsl:for-each select="/csvimport/row">
      <xsl:if test="Status='vater'">
    	<xsl:variable name="grad">
    		<xsl:copy-of select="Begriffsid"/>
    	</xsl:variable>
    ...
    	<element name="begriffsid">
            	<value>
    			<xsl:value-of select="$grad"/>
    		</value>
    	</element>
    				
    <!--	
            <xsl:for-each select="/csvimport/row/Begriffsid=$grad">
    		<element name="kinder">
    			<value>
    			<xsl:value-of select="Benennung"/>
    			</value>
    		</element>
    	</xsl:for-each>
    -->
    ...
      </xsl:if>
    </xsl:for-each>
    Ich dachte, dass es wie in dem kommentierten Teil gehen müsste. Es kommt aber ein Fehler vom XSLT-Prozessor.

    Hat jemand eine Idee?

    Grüße aus FFM

    emka

  • #2
    Gruppieren kann man einfach mit XSLT 2.0 (u.a. unterstützt von Saxon 9 http://saxon.sourceforge.net/ und AltovaXML Tools http://www.altova.com/altovaxml.html):
    Code:
    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="2.0">
      
      <xsl:output indent="yes"/>
      <xsl:strip-space elements="*"/>
      
      <xsl:template match="csvimport">
        <documents>
          <xsl:for-each-group select="row" group-by="Begriffsid">
            <document>
              <xsl:copy-of select="Begriffsid"/>
              <xsl:copy-of select="current-group()[Status = 'vater']/Benennung"/>
              <kinder>
                <xsl:value-of select="current-group()[Status = ('sohn', 'tochter')]/Benennung"
                  separator=", "/>
              </kinder>
            </document>
          </xsl:for-each-group>
        </documents>
      </xsl:template>
    
    </xsl:stylesheet>

    Comment


    • #3
      Hallo Martin,

      danke für die schnelle Antwort! Dein Snippet funktioniert natürlich :-)
      Ich habe auch eine Lösung gefunden. Sieht zwar nicht so schön aus wie Deine - aber sie funktioniert.

      Code:
      <?xml version="1.0" encoding="UTF-8" ?>
      <xsl:stylesheet version="2.0" exclude-result-prefixes="xs xdt err fn" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes" xmlns:err="http://www.w3.org/2005/xqt-errors"><!--<xsl:output indent="yes"/>-->
      	<xsl:output  method="text" indent="no" encoding="ISO-8859-1" media-type="text/plain"/>
      	<xsl:template match="/">
      		<xsl:element name="documents">
      			<xsl:apply-templates/>
      		</xsl:element>
      	</xsl:template>
      <xsl:template match="csvimport">
      <xsl:for-each select="/csvimport/row">
      <xsl:if test="Status='vater'">
      <xsl:variable name="grad">
      <xsl:copy-of select="Begriffsid"/>
      </xsl:variable>
      
      <xsl:value-of select="Benennung"/>[[false,
      <xsl:for-each select="/csvimport/row">
      <xsl:if test="Begriffsid=$grad">
      [<xsl:value-of select="Benennung"/>
      ,1,true],
      </xsl:if>
      </xsl:for-each>
      []]
      </xsl:if>
      </xsl:for-each>
      </xsl:template>
      </xsl:stylesheet>
      Ziel ist es eine Text Datei zu erstellen. Mit dem oberem Skript klappt es auch sehr gut. Das Problem ist jetzt, dass ich es mit den Zeilenumbruch nicht in griff bekomme.

      Die Text Datei sollte wie folgt aussehen:

      Emil[[false,[Frank,1,true],[Martin,1,true]],[]]
      Max[[false,[Thomas,1,true],[Anke,1,true]],[]]

      Sie sieht aber nach der Transformation so aus:
      Emil[[false,

      [Emil
      ,1,true],

      [Frank
      ,1,true],

      [Martin
      ,1,true],

      []]
      Max[[false,

      [Max
      ,1,true],

      [Thomas
      ,1,true],

      [Anke
      ,1,true],

      []]

      Bei Google habe ich bisher nur gefunden wie man Zeilen hinzufügt. Aber nicht wie man sie bei der Ausgabe unterdrücken kann. Bei deinem Skript ,Martin, benutzt als select current-group(). Damit habe ich noch nichts gemacht. Durch den Separator werden die Werte mit einem Komma verbunden. Ich kann also um die einzelnen Werte keine eckigen Klammer setzen, um z.B folgendes zu bekommen:
      [Thomas,1,true],[Anke,1,true]

      Man könnte natürlich wieder mit for-each arbeiten, aber ich befürchte, dass ich dann wieder die Probleme mit dem Zeilenumbruch bekomme.

      Comment


      • #4
        Wenn du text/plain als Resultat willst, warum enthält dein Stylesheet dann ein
        Code:
        <xsl:element name="documents">
        ?
        Das macht keinen Sinn.

        Ansonsten packe deine Texte in xsl: text, also etwa
        Code:
        <xsl:text>[[false,</xsl:text>
        usw., dann werden im Resultat auch keine Zeilenumbrüche auftauchen (solange die nicht explizit innerhalb von xsl: text stehen).

        Comment


        • #5
          Hallo,

          mit <xslt:text> habe ich es auch schon versucht. Aber die Zeilenumbrüche bleiben. Ich habe Dein Script angepasst.

          Code:
          <xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="2.0">
            
            <xsl:output  method="text" indent="no" encoding="ISO-8859-1" media-type="text/plain"/>
            
          <xsl:template match="csvimport">
          <xsl:for-each-group select="row" group-by="Begriffsid">   
          <xsl:for-each select="current-group()[Status = ('vater')]">
          <xsl:value-of select="Benennung"></xsl:value-of>  
          </xsl:for-each>
          <xsl:text>[[false,</xsl:text>
          <xsl:for-each select="current-group()[Status = ('sohn', 'tochter')]">  
          [<xsl:value-of select="Benennung"></xsl:value-of>,1,true]
          <xsl:if test="not(position()=last())">
          <xsl:text>,</xsl:text>
          </xsl:if>
          </xsl:for-each><xsl:text>],[]]
          </xsl:text>
          </xsl:for-each-group>
          </xsl:template>
          
          </xsl:stylesheet>
          und es liefert folgendes:

          Emil[[false,
          [Frank,1,true]
          ,
          [Martin,1,true]
          ],[]]
          Max[[false,
          [Thomas,1,true]
          ,
          [Anke,1,true]
          ],[]]


          Irgendwas muss beim durchlaufen der for-each Schleife einen Zeilenumbruch auslösen. Aber nur was? Leider bin ich noch nicht fündig geworden.

          Comment


          • #6
            Du musst xsl: text schon konsequent anwenden:
            Code:
            <xsl:template match="csvimport">
            <xsl:for-each-group select="row" group-by="Begriffsid">   
            <xsl:for-each select="current-group()[Status = ('vater')]">
            <xsl:value-of select="Benennung"></xsl:value-of>  
            </xsl:for-each>
            <xsl:text>[[false,</xsl:text>
            <xsl:for-each select="current-group()[Status = ('sohn', 'tochter')]">  
              <xsl:text>[</xsl:text>
              <xsl:value-of select="Benennung"/>
              <xsl:text>,1,true]</xsl:text>
            <xsl:if test="not(position()=last())">
            <xsl:text>,</xsl:text>
            </xsl:if>
            </xsl:for-each><xsl:text>],[]]
            </xsl:text>
            </xsl:for-each-group>
            </xsl:template>

            Comment


            • #7
              Das lässt sich dann etwas kompakter schreiben:
              Code:
              <xsl:template match="csvimport">
                <xsl:for-each-group select="row" group-by="Begriffsid">   
                  <xsl:for-each select="current-group()[Status = ('vater')]">
                    <xsl:value-of select="Benennung"></xsl:value-of>  
                  </xsl:for-each>
                  <xsl:text>[[false,</xsl:text>
                  <xsl:value-of 
                    select="current-group()[Status = ('sohn', 'tochter')]/Benennung/concat('[', ., ',1,true]')"
                    separator=","/>
                  <xsl:text>],[]]
              </xsl:text>
                </xsl:for-each-group>
              </xsl:template>

              Comment


              • #8
                Stimmt! Was so ein kleine Unaufmerksamkeit alles aus macht!
                So funktioniert es tadellos!
                Danke für Deine Hilfe!

                emka

                Comment

                Working...
                X