Announcement

Collapse
No announcement yet.

Stack mit XSLT

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

  • Stack mit XSLT

    Hallo,

    stehe vor der Aufgabe aus einem unstrukturierten Text Klammerausdrücke zu parsen und nach XML zu verarbeiten zu müssen. Normaler Weise würde ich für eine solche Aufgabe Perl, Python oder Java nehmen nur steht das im Kontext nicht zu Verfügung.
    Das Problem ist, jeweils die öffnenden der schließenden Klammer zuzuordenen.
    z.B.:
    (a * b - (c+d) )
    Die Klammern können beliebig tief verschachtelt sein.
    Daraus sollte sowas ähnliches entstehen:
    Code:
    <bracket>
      <c>a</c>
      <o>*</o>
      <c>b</c>
      <bracket>
        <c>c</c>
        <o>+</o>
        <c>d</c>
      </bracket>
    </bracket>
    Bei Sprachen, wie z.B Java würde man nun mit Hilfe einer Stack-Struktur
    das lösen. Wie könnte man das Problem der Klammer-Zuordnung mit XSLT lösen? Kann man einen Stack nachbilden? Oder gibt es dafür eine andere Lösung?
    Den Text hole ich mir mit:
    Code:
    <xsl:analyze-string
        select="unparsed-text('text.txt','UTF-8')"
        regex="...">
        <xsl:matching-substring>
             ?
        </xsl:matching-substring>
        <xsl:non-matching-substring>
             ?
        </xsl:non-matching-substring>
    Ich bin bei dieser Verfahrensweise auch nicht sicher, ob man mit einem regex
    auskommen könnte und das dann rekursiev aufruft???

    Für jeden Hinweis und/oder Idee wäre ich wirklich sehr dankbar.

    vielen Dank

    Micha

  • #2
    Hi,

    Wenn es nicht auf Fehleranalyse ankommt, so würde ich einfach die gegebene Funktion mittels eines Templates rekursiv abarbeiten:

    z.B:
    Code:
        <xsl:template name="scanner">
            <xsl:param name="function"></xsl:param>
    
            <!--xsl:message><xsl:value-of select="$function" /></xsl:message-->
            <xsl:variable name="length"><xsl:value-of select="string-length($function)" /></xsl:variable>
            <xsl:if test="number($length) &gt; 0">
                <xsl:variable name="currentChar"><xsl:value-of select="substring($function, 1,1)" /></xsl:variable>
    
                <xsl:choose>
                    <xsl:when test="$currentChar = '('">
                        <bracket>
                            <xsl:call-template name="scanner">
                                <xsl:with-param name="function"><xsl:value-of select="substring($function, 2, $length)" /></xsl:with-param>
                            </xsl:call-template>
                        </bracket>
                    </xsl:when>
                    <xsl:when test="contains('+*-/', $currentChar)">
                        <op>
                            <xsl:value-of select="$currentChar" />
                        </op>
                        <xsl:call-template name="scanner">
                            <xsl:with-param name="function"><xsl:value-of select="substring($function, 2, $length)" /></xsl:with-param>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:when test="contains('abc', $currentChar)">
                        <c>
                            <xsl:value-of select="$currentChar" />
                        </c>
                        <xsl:call-template name="scanner">
                            <xsl:with-param name="function"><xsl:value-of select="substring($function, 2, $length)" /></xsl:with-param>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:call-template name="scanner">
                            <xsl:with-param name="function"><xsl:value-of select="substring($function, 2, $length)" /></xsl:with-param>
                        </xsl:call-template>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:if>
        </xsl:template>
    MfG

    Comment


    • #3
      Da XSLT 2.0 offenbar möglich ist, hier ein Ansatz mit fn:replace() und regulären Ausdrücken. Die einzelnen Variablen in den Formeln sind auf [a-z] bezogen:

      Code:
      <?xml version="1.0" encoding="ISO-8859-1"?>
      <xsl:stylesheet version="2.0" 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"
        exclude-result-prefixes="fn xs">
      
        <xsl:output method="xml" version="1.0" encoding="ISO-8859-1"
          indent="yes" use-character-maps="brackets_operators"/>
      
        <xsl:character-map name="brackets_operators">
          <xsl:output-character character="&#xE001;" string="&lt;bracket>"/>
          <xsl:output-character character="&#xE002;" string="&lt;/bracket>"/>
      
          <xsl:output-character character="&#xE003;" string="&lt;o>"/>
          <xsl:output-character character="&#xE004;" string="&lt;/o>"/>
      
          <xsl:output-character character="&#xE005;" string="&lt;c>"/>
          <xsl:output-character character="&#xE006;" string="&lt;/c>"/>
        </xsl:character-map>
      
      
        <xsl:template match="/">
      
          <xsl:variable name="formel_in" select="'(a * b - (c + d))'"/>
      
          <xsl:variable name="formel_temp1"
             select="fn:replace(fn:replace($formel_in,'\(','&#xE001;'),'\)','&#xE002;')"/>
      
          <xsl:variable name="formel_temp2"
             select="fn:replace($formel_temp1,'([\+\-\*/])','&#xE003;$1&#xE004;')"/>
      
          <xsl:variable name="formel_out"
             select="fn:replace($formel_temp2,'([a-z])','&#xE005;$1&#xE006;')"/>
      
          <xsl:value-of select="$formel_out"/>
      
        </xsl:template>
       
      </xsl:stylesheet>
      Zuletzt editiert von Thomas Meinike; 02.01.2008, 11:27.

      Comment


      • #4
        Hallo Thomas,

        vielen Dank für die Lösungsvorschläge. Ich hatte ursprünglich in eine etwas andere Richtung gedacht, war aber glaube ich ein "Irrweg". Ich dachte man könnte das mit einem einzigen regulären Ausdruck (den man rekursiv aufruft) quasi von innen nach aus außen abarbeiten, habe mich damit aber verzettelt.
        die Reihenfolge vom Match und ersetzen wäre dann so:

        (a * b - (c+d) )
        -> (a * b -<bracket><c>c</c><o>+</o><c>d</c></bracket>)
        -> <bracket><c>a</c><o>*</o><c>b</c><bracket><c>c ...

        Das hätte vielleicht Vorteile für die Fehleranalyse gehabt?
        Nun werde ich das aber wohl so machen, wie du es vorgeschlagen hast.
        (Das heist die Formeln von links nach rechts abarbeiten)
        Die Fehleranalyse delegiere ich dann eben zum generierten XML mit Schema.

        In diesem Zusammenhang habe ich doch noch eine kleine Frage:
        Gibt es eigentlich eine einfache Möglichkeit an die Zeilennummer des aktuellen Knotens von einem Quell-Dokument heran zu kommen?

        vielen Dank und viele Grüße

        Micha

        P.S.: und natürlich ein frohes, gesundes neues Jahr

        Comment


        • #5
          Gleichfalls beste Wünsche für das neue Jahr @all.

          Vielleicht hilft dieser Artikel bezüglich der Zeilennummern.

          Comment


          • #6
            genau so etwas suchte ich

            nochmals vielen Dank.

            Gruß Micha

            Comment

            Working...
            X