Paul Brunner: Auf Text-Knoten überprüfen

Hallo zusammen,

ich hänge mal wieder mit dem XPath-Syntax.Ich möchte abfragen ob der Inhalt des aktuellen Knotens ein Text oder weiters Knoten sind:

<xsl:if test="child::text()"> sollt doch eigentlich gehen?

Beispiel:
<xsl:template match="person">
<xsl:if test="child::text()">
  <xsl:value-of select="."/>
</input></p>
</xsl:if>
</xsl:template>

Fall1: Hier soll der Knoten <person> verarbeitete werden
<person>Paul Brunner</person>

Fall2: Hier soll der Knoten <person> nicht_verarbeitete werden
<person>
 <name>Brunner</name>
 <vorname>Paul</vorname>
</person>

Danke
Paul

  1. Hallo Paul,

    ich MUSS jetzt einfach antworten !! Auch wenn ich Dir nicht weiterhelfen kann...

    Denn das kann kein Zufall sein, daß wir fast zur selben Minute ins selbe Forum posten !!!

    Deshalb nur kurz: Hallo Namensvetter !

    Viele Grüße, Matthias Brunner

  2. hallo Paul,

    ich hänge mal wieder mit dem XPath-Syntax.Ich möchte abfragen ob der Inhalt des aktuellen Knotens ein Text oder weiters Knoten sind:

    <xsl:if test="child::text()"> sollt doch eigentlich gehen?

    ja, nd es tut das auch.

    Beispiel:
    <xsl:template match="person">
    <xsl:if test="child::text()">
      <xsl:value-of select="."/>
    </input></p>

    ^^^^^^^^^^^^
    das solltest du in der form eher nicht machen.

    </xsl:if>
    </xsl:template>

    -----------xml----------
    <?xml version="1.0"?>
    <document>
    <person>
     <name>Brunner</name>
     <vorname>Paul</vorname>
    </person>
    <person>Paul Brunner</person>
    </document>
    ------------------------
    ------------ in der  xsl datei -------------
    <xsl:template match="person">
    <p>
    <xsl:if test="child::text()">
      <xsl:value-of select="."/> [<xsl:value-of select="position()" />]
    </xsl:if>
    </p>
    <p>
    <xsl:if test="not(child::text())">
      nicht text [<xsl:value-of select="position()" />]
    </xsl:if>
    </p>
    --------------------------------------------

    was genau funktioniert nicht so wie du es willst?

    grüße
    thomas
    </xsl:template>

    1. Hallo Thomas,

      ja, nd es tut das auch.
      was genau funktioniert nicht so wie du es willst?

      er parst beide tags (Fall1 und Fall2)

      </input></p>
         ^^^^^^^^^^^^
      das solltest du in der form eher nicht machen.

      muss so sein, sonst moniert der xslt-Prozessor das fehlende End-tag
      mit <xsl:output method="html" indent="yes" /> ist die Ausgabe dann wieder html-konform.

      Gruß
      Paul

      Hier nochmal das komplette Sheet:

      <?xml version="1.0" encoding="ISO-8859-1"?>
      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="html" indent="yes" />

      <xsl:template match="/">
           <xsl:for-each select="//*">
          <xsl:variable name="position" select="position()"/>
             <xsl:call-template name="tag">
           <xsl:with-param name="id" select="$position"/>
          </xsl:call-template>
           <xsl:for-each select="@*">
          <xsl:call-template name="att">
             <xsl:with-param name="id" select="$position"/>
            </xsl:call-template>
         </xsl:for-each>
           </xsl:for-each>
      </xsl:template>

      <xsl:template name="att">
      <xsl:param name="id"/>
      <p> <xsl:attribute name="class">formfield</xsl:attribute>
       <xsl:value-of select="name()"/>xsl:text: </xsl:text>
      <input>
       <xsl:attribute name="name">@<xsl:value-of select="local-name()"/><xsl:value-of select="$id"/></xsl:attribute>
       <xsl:attribute name="value"><xsl:value-of select="."/></xsl:attribute>
      </input></p>
      </xsl:template>

      <xsl:template name="tag">
      <xsl:param name="id"/>
      <xsl:if test="child::text()">
      <p> <xsl:attribute name="class">formfield</xsl:attribute>
       <xsl:value-of select="name()"/>xsl:text: </xsl:text>
      <input>
       <xsl:attribute name="name"><xsl:value-of select="local-name()"/><xsl:value-of select="$id"/></xsl:attribute>
       <xsl:attribute name="value"><xsl:value-of select="."/></xsl:attribute>
      </input></p>
      </xsl:if>
      </xsl:template>

      </xsl:stylesheet>

      1. hallo Paul,

        ja, nd es tut das auch.
        was genau funktioniert nicht so wie du es willst?
        er parst beide tags (Fall1 und Fall2)

        ja natürlich: <xsl:template match="person"> trifft ja auf alle person elemente (mit oder ohne kinderelemente.

        </input></p>
           ^^^^^^^^^^^^
        das solltest du in der form eher nicht machen.

        muss so sein, sonst moniert der xslt-Prozessor das fehlende End-tag

        nur in deinem ersten code fehlen die start tags.

        Hier nochmal das komplette Sheet:

        <xsl:template name="tag">
        <xsl:param name="id"/>
        <xsl:if test="child::text()">
        <p> <xsl:attribute name="class">formfield</xsl:attribute>
        <xsl:value-of select="name()"/>xsl:text: </xsl:text>
        <input>
        <xsl:attribute name="name"><xsl:value-of select="local-name()"/><xsl:value-of select="$id"/></xsl:attribute>
        <xsl:attribute name="value"><xsl:value-of select="."/></xsl:attribute>
        </input></p>
        </xsl:if>
        </xsl:template>

        hm... ich verstehe nicht was daran nicht funktioniert. es wird nur dann etwas geschrieben, wenn der kindknoten ein text ist. das funktioniert bei mir sowohl mit saxon als auch mit dem IE.

        ------
        <?xml version="1.0"?>
        <document>
         <header>
          <name>Ein Dokument</name>
          <title>Untertitel</title>
          <date>20020518</date>
          <author>ich</author>
          <author><text></text></author>
          <author><text2>222222222222</text2></author>
         </header>
         <content>
           <text>blabla</text>
         </content>
        </document>
        --------------

        grüße
        thomas

        ps: output vom saxon:
        --------------------------
        <p class="formfield">document: <input name="document1" value="&#xA; &#xA;  Ein Dokument&#xA;  Untertitel&#xA;  20020518&#xA;  ich&#xA;    &#xA;     222222222222&#xA; &#xA; &#xA;   blabla&#xA; &#xA;"></p>
        <p class="formfield">header: <input name="header2" value="&#xA;  Ein Dokument&#xA;  Untertitel&#xA;  20020518&#xA;  ich&#xA;    &#xA;     222222222222&#xA; "></p>
        <p class="formfield">name: <input name="name3" value="Ein Dokument"></p>
        <p class="formfield">title: <input name="title4" value="Untertitel"></p>
        <p class="formfield">date: <input name="date5" value="20020518"></p>
        <p class="formfield">author: <input name="author6" value="ich"></p>
        <p class="formfield">text2: <input name="text210" value="222222222222"></p>
        <p class="formfield">content: <input name="content11" value="&#xA;   blabla&#xA; "></p>
        <p class="formfield">text: <input name="text12" value="blabla"></p>

        1. Hallo Nachtmensch,

          danke für deine frühe (oder doch späte?) Antwort.

          hm... ich verstehe nicht was daran nicht funktioniert. es wird nur dann etwas geschrieben, wenn der kindknoten ein text ist. das funktioniert bei mir sowohl mit saxon als auch mit dem IE.

          Da habe ich mich wohl etwas mistverständlich ausgedrückt.
          Ich möchte nur den Inhalt der Tags ausgeben, die unmittelbar text enthalten. Die Ausgabe von <dokument>, <header> und <content> (im unteren Beispiel auch die des 2. und 3. <author> tags) soll per <xsl:if test="child::text()"> unterdrückt werden. Klar, da macht das editieren der zusammen gemischten Inhalte in einem Formularfeld ja auch keinen Sinn.

          Gruß
          Paul


          <?xml version="1.0"?>
          <document>
          <header>
            <name>Ein Dokument</name>
            <title>Untertitel</title>
            <date>20020518</date>
            <author>ich</author>
            <author><text></text></author>
            <author><text2>222222222222</text2></author>
          </header>
          <content>
             <text>blabla</text>
          </content>
          </document>

          ps: output vom saxon:

          <p class="formfield">document: <input name="document1" value="&#xA; &#xA;  Ein Dokument&#xA;  Untertitel&#xA;  20020518&#xA;  ich&#xA;    &#xA;     222222222222&#xA; &#xA; &#xA;   blabla&#xA; &#xA;"></p>
          <p class="formfield">header: <input name="header2" value="&#xA;  Ein Dokument&#xA;  Untertitel&#xA;  20020518&#xA;  ich&#xA;    &#xA;     222222222222&#xA; "></p>
          <p class="formfield">name: <input name="name3" value="Ein Dokument"></p>

          1. Hallo Nachtmensch,

            danke für deine frühe (oder doch späte?) Antwort.

            hm... ich verstehe nicht was daran nicht funktioniert. es wird nur dann etwas geschrieben, wenn der kindknoten ein text ist. das funktioniert bei mir sowohl mit saxon als auch mit dem IE.

            Da habe ich mich wohl etwas mistverständlich ausgedrückt.
            Ich möchte nur den Inhalt der Tags ausgeben, die unmittelbar text enthalten. Die Ausgabe von <dokument>, <header> und <content> (im unteren Beispiel auch die des 2. und 3. <author> tags) soll per <xsl:if test="child::text()"> unterdrückt werden. Klar, da macht das editieren der zusammen gemischten Inhalte in einem Formularfeld ja auch keinen Sinn.

            Gruß
            Paul


            <?xml version="1.0"?>
            <document>
            <header>
              <name>Ein Dokument</name>
              <title>Untertitel</title>
              <date>20020518</date>
              <author>ich</author>
              <author><text></text></author>
              <author><text2>222222222222</text2></author>
            </header>
            <content>
               <text>blabla</text>
            </content>
            </document>

            ps: output vom saxon:

            <p class="formfield">document: <input name="document1" value="&#xA; &#xA;  Ein Dokument&#xA;  Untertitel&#xA;  20020518&#xA;  ich&#xA;    &#xA;     222222222222&#xA; &#xA; &#xA;   blabla&#xA; &#xA;"></p>
            <p class="formfield">header: <input name="header2" value="&#xA;  Ein Dokument&#xA;  Untertitel&#xA;  20020518&#xA;  ich&#xA;    &#xA;     222222222222&#xA; "></p>
            <p class="formfield">name: <input name="name3" value="Ein Dokument"></p>

          2. Hallo Nachtmensch,

            Hi, sorry für den Fehlschuß, da wurde irgendwie der Submit zu früh ausgelöst...

            danke für deine frühe (oder doch späte?) Antwort.

            hm... ich verstehe nicht was daran nicht funktioniert. es wird nur dann etwas geschrieben, wenn der kindknoten ein text ist. das funktioniert bei mir sowohl mit saxon als auch mit dem IE.

            Da habe ich mich wohl etwas mistverständlich ausgedrückt.
            Ich möchte nur den Inhalt der Tags ausgeben, die unmittelbar text enthalten. Die Ausgabe von <dokument>, <header> und <content> (im unteren Beispiel auch die des 2. und 3. <author> tags) soll per <xsl:if test="child::text()"> unterdrückt werden. Klar, da macht das editieren der zusammen gemischten Inhalte in einem Formularfeld ja auch keinen Sinn.

            wieviele verschiedene Kindelemente gibt es?
            Bei kleiner Anzahl und bekannten Elementnamen könnte man sowas probieren:

            if test="! (child::elem1 | child::elem2 | child::elem3)"
            (wobei ich im Moment die genaue Syntax von NOT, AND und OR nicht weiß, hab schon länger kein XSL mehr gemacht)

            Gruß
            Paul

            Andreas

            1. Hallo Andreas,

              das ganze soll für beliebige Elementknoten mit ausschließlichem Textinhalt funktionieren.

              Dank dir trotzdem
              Paul

          3. Hallo Paul,

            Da habe ich mich wohl etwas mistverständlich ausgedrückt.
            Ich möchte nur den Inhalt der Tags ausgeben, die unmittelbar text enthalten. Die Ausgabe von <dokument>, <header> und <content> (im unteren Beispiel auch die des 2. und 3. <author> tags) soll per <xsl:if test="child::text()"> unterdrückt werden. Klar, da macht das editieren der zusammen gemischten Inhalte in einem Formularfeld ja auch keinen Sinn.


            <?xml version="1.0"?>
            <document>
            <header>
              <name>Ein Dokument</name>
              <title>Untertitel</title>
              <date>20020518</date>
              <author>ich</author>
              <author><text></text></author>
              <author><text2>222222222222</text2></author>
            </header>
            <content>
               <text>blabla</text>
            </content>
            </document>

            Wenn du keinen gemischten Inhalt hast, dann hilft Dir die Abfrage, die ich bereits unten gepostet habe:

            http://forum.de.selfhtml.org/?m=68941&t=12399

            Gruß
            Franz

            1. Hallo,

              des Rätsels Lösung: text() reagierts auch auf Absatzmarken und Tabulatoren. (zumindest bei sablotron)

              Also sowohl mit
              <xsl:if test="child::text()"> als auch
              <xsl:if test="./node()[1]=text()">

              ----
              <person><name>Brunner</name><vorname>Paul</vorname></person>
              ----
              geht

              ----
              <person>
               <name>Brunner</name>
               <vorname>Paul</vorname>
              </person>
              ----
              geht nicht!

              Folgefrage:
              Wie codiere ich bei translate() Sonderzeichen?

              Gruß
              Paul

              1. Hallo,

                des Rätsels Lösung: text() reagierts auch auf Absatzmarken und Tabulatoren. (zumindest bei sablotron)

                Also sowohl mit
                <xsl:if test="child::text()"> als auch
                <xsl:if test="./node()[1]=text()">


                <person><name>Brunner</name><vorname>Paul</vorname></person>

                geht


                <person>
                <name>Brunner</name>
                <vorname>Paul</vorname>
                </person>

                geht nicht!

                Ja, richtig, das wird es sein

                Hast Du es schonmal mit dem Top-Level-Element xsl:strip-space versucht? Es hat ein Attribut namens "element", das eine durch Leerzeichen getrennte Liste der Elementnamen aufnimmt, bei denen die Whitespace-Knoten entfernt werden sollen.

                <xsl:strip-space name="person"> könnte Dir also helfen. Vielleicht geht auch <xsl:strip-space name="*"> für alle Elemente. Das wäre die einfachste Lösung. Kann es hier gerade nicht ausprobieren.

                Folgefrage:
                Wie codiere ich bei translate() Sonderzeichen?

                Hm, mit Zeichenreferenzen und Unicode-Nummer. Also für Whitespace:

                tab #x9
                newline #xA
                Carriage Return #xD
                space #x20

                Gruß
                Franz

                Gruß
                Paul

                1. Hallo Franz,

                  <xsl:strip-space name="person"> könnte Dir also helfen. Vielleicht geht auch <xsl:strip-space name="*"> für alle Elemente.

                  <xsl:strip-space elements="*" />
                  strip vor der Transformation aber nach der Erstellung des Ergebnisbaumes, also zu spät.

                  Aber so gehts jetzt:
                  <xsl:if test="translate(current(), '#x9#xA#xD#x20', '' )=text()">

                  Dank allen für Hilfe und Anregungen
                  Paul