Announcement

Collapse
No announcement yet.

Inhalt zwischen Start- und Ende-Tags gruppieren

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

  • Inhalt zwischen Start- und Ende-Tags gruppieren

    Hallo zusammen,

    ich möchte per xslt Inhalte, die zwischen Start und Ende-Tags stehen zusammen gruppieren. Alle anderen Elemente sollen "normal" gemäß ihren template-Regeln verarbeitet werden.

    z.B.
    <section>
    <p>
    <div_start/>
    <ul>..</ul>
    <img/>
    <cont_start/><p><cont_end/>
    <div_end/>
    <img>
    <p>
    <ol>...</ol>
    <div_start/>
    <table>...</table>
    <img/>
    <tab_start/><p><tab_end/>
    <div_end/>
    </section>

    sollte transformiert werden in:

    <section>
    <p>
    <div>
    <ul>..</ul>
    <img/>
    <cont><p></cont>
    </div>
    <img>
    <p>
    <ol>...</ol>
    <div>
    <table>...</table>
    <img/>
    <tab><p></tab>
    </div>
    </section>

    Ich habe schon versucht, das Anfangs- und Ende-Tag über <xsl:text disable-output-escaping="yes"> schreiben, aber das scheint mir eine denkbar schlechte Lösung. Kann jemand Ideen, Denkanstöße geben?

  • #2
    Bitte benutze http://entwickler-forum.de/misc.php?do=bbcode#code, um deine XML-Beispiele zu posten.
    Und wir müssen für solche Aufgabenstellung zuerst ein wohlgeformtes XML-Dokument sehen, denn
    Code:
    <section>
    <p>
    <div_start/>
    <ul>..</ul>
    <img/>
    <cont_start/><p><cont_end/>
    <div_end/>
    <img>
    <p>
    <ol>...</ol>
    <div_start/>
    <table>...</table>
    <img/>
    <tab_start/><p><tab_end/>
    <div_end/>
    </section>
    ist keines, das "p"-Element nach dem "section" ist nirgendwo geschlossen, und das "img" nach dem ersten "</div_end>" auch nicht.
    Und dann erkläre noch, ob du XSLT 2.0 oder 1.0 zu Lösung einsetzen willst, 2.0 hat mit for-each-group wesentlich mächtigere Werkzeuge zum Gruppieren.

    Comment


    • #3
      Angenommen, das Eingabedokument hat die Form
      Code:
      <section>
      <p>
      <div_start/>
      <ul>..</ul>
      <img/>
      <cont_start/><p>..</p><cont_end/>
      <div_end/>
      <img/>
      </p>
      <ol>...</ol>
      <div_start/>
      <table>...</table>
      <img/>
      <tab_start/><p>..</p><tab_end/>
      <div_end/>
      </section>
      dann kann man mit XSLT 2.0 und Saxon 9 (http://saxon.sourceforge.net/) und einem Stylesheet wie
      Code:
      <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:mf="http://example.com/mf"
        exclude-result-prefixes="xs mf"
        version="2.0">
        
        <xsl:param name="suffix1" as="xs:string" select="'_start'"/>
        <xsl:param name="suffix2" as="xs:string" select="'_end'"/>
        
        <xsl:param name="wrapper-names" as="xs:string+" select="'div', 'cont', 'tab'"/>
        
        <xsl:function name="mf:wrap" as="node()*">
          <xsl:param name="input" as="node()*"/>
          <xsl:param name="current-wrapper-names" as="xs:string*"/>
          <xsl:variable name="wrapper-name1" as="xs:string?" select="$current-wrapper-names[1]"/>
          <xsl:choose>
            <xsl:when test="$wrapper-name1">
              <xsl:variable name="start-name" as="xs:string" select="concat($wrapper-name1, $suffix1)"/>
              <xsl:variable name="end-name" as="xs:string" select="concat($wrapper-name1, $suffix2)"/>
      
              <xsl:for-each-group select="$input" group-starting-with="*[local-name() eq $start-name]">
                <xsl:choose>
                  <xsl:when test="self::*[local-name() eq $start-name]">
                    <xsl:variable name="end-element" as="element()" 
                      select="current-group()[self::*[local-name() eq $end-name]][1]"/>
                    <xsl:element name="{$wrapper-name1}">
                      <xsl:sequence select="mf:wrap(current-group()[. &lt;&lt; $end-element] except ., $wrapper-names)"/>
                    </xsl:element>
                    <xsl:sequence select="mf:wrap(current-group()[. &gt;&gt; $end-element], $current-wrapper-names[position() gt 1])"/>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:sequence select="mf:wrap(current-group(), $current-wrapper-names[position() gt 1])"/>
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:for-each-group>
           </xsl:when>  
            <xsl:otherwise>
              <xsl:apply-templates select="$input"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:function>
        
        <xsl:template match="*">
          <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:sequence select="mf:wrap(node(), $wrapper-names)"/>
          </xsl:copy>
        </xsl:template>
        
      </xsl:stylesheet>
      folgende Ausgabe erreichen:
      Code:
      <section>
      <p>
      <div>
      <ul>..</ul>
      <img/>
      <cont><p>..</p></cont>
      </div>
      <img/>
      </p>
      <ol>...</ol>
      <div>
      <table>...</table>
      <img/>
      <tab><p>..</p></tab>
      </div>
      </section>

      Comment

      Working...
      X