Announcement

Collapse
No announcement yet.

Ancestor, aber nicht alle, sondern nur der direkte erste

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

  • Ancestor, aber nicht alle, sondern nur der direkte erste

    Hallo,

    leider bin ich xslt technisch ziemlich grün hinter den Ohren. Bisher habe ich mich recht gut durch geschlagen, auch wenn es den Profis dabei sicherlich anders wird.

    Ich suche nach einer Lösung, mit der ich aus einem xml-Dokument Informationen aus unterschiedlichen Hierarchien auslesen kann.

    Auszug XML-Formular:
    Code:
    <Activity> x-verschiedene Vorgänge
      <flagStatus>
      <wbsCode>
      <title>
      <elements>
        <reviewDate>
        <CheckListEntry>
          <title>
          <entryDescription>
    <subtitle>

    Ich habe mich entschieden CheckList als Mittelpunkt/ -knoten zu nehmen. Zu diesem Unterpunkt CheckList gibt es aber spez. Informationen aus dem übergeordneten Knoten, bspw. title der Activity oder wbsCode der Activity.
    Wie kann ich genau diese Informationen auslesen? Mit ancestor bekomme ich die Infos aller anderen Activity. Gibt es ein Kommando für den direkt übergeordneten Knoten, o.ä.?
    Wie gesagt, ich habe selbst keine Kenntnisse in XSLT. Das, was mein Stylesheet bisher beinhaltet mag für die geschulten Leser haarsträubend sein, das bitte ich zu entschuldigen, hoffe aber, dass meine Problematik rübergekommen ist. Tausend Dank.


    Mein Stylesheet-Versuch:
    Code:
    		<xsl:for-each select="//Activity/elements/CheckList">
    		<xsl:sort select="wbsCode"/>
    		<tr class="r{position() mod 2}">
    		<td valign="top" align="center" width="5%">
    				<xsl:if test="flagStatus = 'red'">
    					<img src="rsc/flag_red.gif" />
    				</xsl:if>
    				<xsl:if test="flagStatus = 'yellow'">
    					<img src="rsc/flag_yellow.gif" />
    				</xsl:if>
    				<xsl:if test="flagStatus = 'green'">
    					<img src="rsc/flag_green.gif" />
    				</xsl:if>
    			</td>
    		<td valign="top" align="left" width="10%"><xsl:value-of select="ancestor::Activity/wbsCode"/></td>
    			<td valign="top" align="left" width="10%"><xsl:value-of select="ancestor::Activity/title"/></td>
    			<td valign="top" align="left" width="10%"><xsl:value-of select="format-dateTime(reviewDate, $dateFormatter )"/></td>
    			<td valign="top" align="left" width="15%"><xsl:if test="title='Schnittstellen'">
    			<xsl:for-each select="CheckListEntry">
    				<xsl:choose>
    				<xsl:when test="isChecked">
    					<img src="rsc/RadioBoxChecked.gif" /> 
    				</xsl:when>
    				<xsl:otherwise>
    					<img src="rsc/RadioBoxUnchecked.gif" /> 
    				</xsl:otherwise>
    				</xsl:choose>
    					<xsl:value-of select="title"/><br />				
    				</xsl:for-each>
    				</xsl:if>
    				</td>
    			<td valign="top" align="left" width="15%"><xsl:value-of select="CheckListEntry/entryDescription"/><br />
    			</td>
    			<td valign="top" align="left" width="10%"><xsl:value-of select="ancestor::Activity/subtitle"/></td>
    		</tr>
    		</xsl:for-each>
    	</xsl:if>

  • #2
    Ich sehe in der XML-Struktur kein CheckList-Element. Das direkt übergeordnete Element lässt sich über die parent-Achse, kurz .. ansprechen.

    Comment


    • #3
      Das ist richtig, ich habe es fehlerhaft eingestellt:

      Code:
      <Activity> x-verschiedene Vorgänge
        <flagStatus>
        <wbsCode>
        <title>
        <elements>
          <CheckList>
            <reviewDate>
            <CheckListEntry>
              <title>
              <entryDescription>
      Mit parent habe ich es versucht, komme damit aber auch nicht weiter. Meine Abfrage sieht dann so aus:

      Code:
      <xsl:value-of select="parent::Activity/wbsCode"/>
      Ergebnis hierfür ist ein leeres Feld.

      Comment


      • #4
        Activity liegt zwei Ebenen über CheckList. Andererseits ist wbsCode ein Geschwisterelement von elements. Diese beiden Abfragen sollten zum Ziel führen:

        Code:
        <xsl:value-of select="../../wbsCode"/>
        
        <xsl:value-of select="../preceding-sibling::wbsCode"/>

        Comment


        • #5
          Wenn Sie wüssten, wie lange ich daran schon rumkrebse...

          Ist doch immer wieder schön, wenn Lösungen simpel aussehen und funktionieren.

          Tag gerettet, Tausend Dank!
          Jetzt weiss ich ja, wohin ich mich wenden kann.

          Comment


          • #6
            ??

            Hallo!

            Frage Nr.1: was war eigentlich an "parent" oder "ancestor" falsch? Bei mir klappt es nämich auch nicht.

            Frage Nr.2: was für Gründe könnte es geben, wieso es auch mit der Pfadangabe "../" nicht klappt?

            Angelehnt an das Beispiel oben, kann ich noch nicht einmal von <title> auf <wbsCode> zugreifen. Das wäre ja (nein, ich kann/möchte nicht preceding-sibling benutzen)
            Code:
            <xsl:value-of select="../wbsCode"/>
            Es ist nur ein vereinfachtes Beispiel. Eigentlich muss ich 4 Parent-Knoten zurückgehen und dann 3 Knoten an einer anderen Stelle wieder rein, um den Wert dort auszulesen.

            Mein Ansatz war ähnlich wie:
            Code:
            <xsl:value-of select="ancestor::*[4]/activity/elements/checklist
            oder
            Code:
            <xsl:value-of select="../../../../activity/elements/checklist
            Beides geht nicht. Wie gesagt, auch eine Ebene höher komme ich gerade nicht. Woran liegt das? Ich benutze Altova XMLSPy 2008.

            Vielen Dank im Voraus!
            Zuletzt editiert von w_ing; 06.04.2010, 19:53.

            Comment


            • #7
              Poste mal minimale aber komplette XML und XSLT Beispiele, die uns erlauben, das Problem zu reproduzieren. Im Beispiel des Erstellers dieses Threads ist ja ein Elementname z.B. "CheckList", da wird der XPath "checklist" dann mit Sicherheit nicht zum Erfolg führen können.

              Comment


              • #8
                ... an Klein/Großschreibung liegt es nicht...

                xml:
                Code:
                <?xml version="1.0" encoding="UTF-8"?>
                <garage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                	<marken>
                		<lkw_marke>MAN</lkw_marke>
                		<pkw_marke>Mercedes</pkw_marke>
                	</marken>
                	<autos>
                		<auto>
                			<auto_daten>
                				<lasten_transport>lkw</lasten_transport>
                				<personen_transport>pkw</personen_transport>										
                			</auto_daten>
                		</auto>
                	</autos>
                </garage>
                xslt:
                Code:
                
                <?xml version="1.0" encoding="UTF-8"?>
                <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">
                	<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
                	
                	<xsl:template match="/">
                             <body>
                		<!-- was anderes -->
                		<xsl:call-template name="getMarke"/>
                		<!-- was anderes -->
                             </body>
                	</xsl:template>
                	
                	<xsl:template name="getMarke">
                		<xsl:variable name="marke">
                			<xsl:choose>
                				<xsl:when test="contains(name(.), 'personen')">
                				<!-- weiß ich nicht -->
                				</xsl:when>
                				<xsl:when test="contains(name(.), 'lasten')">
                				<!-- weiß ich nicht -->
                				</xsl:when>
                			</xsl:choose>
                		</xsl:variable>
                		<xsl:value-of select="$marke"/>
                	</xsl:template>	
                </xsl:stylesheet>
                
                Da, wo "weiß ich nicht" kommt, müsste der Befehl kommen, mit dem auf die Automarke des jeweiligen Fahrzeugs zugreifen würde. Sprich der value-of Befehl müsste entweder "MAN" oder "Mercedes" als Ergebnis liefern.

                Template <xsl:call-template name="getMarke"/> wird entweder beim Knoten <lasten_transport> oder <personen_transport> aufgerufen. name(.) ist also entweder "lasten_transport" oder eben "personen_transport"

                Danke!
                Zuletzt editiert von w_ing; 06.04.2010, 23:51.

                Comment


                • #9
                  komisch...

                  Das ist komisch. Dieser Zugriff hier funktioniert:
                  Code:
                  <xsl:value-of select="../../../../*[contains(name(.), 'marken')]/*[contains(name(.), 'pkw_marke')]"/>
                  Ich vermute, dass mit der XML Datei etwas nicht stimmt. Sprich, die Namespaces sind so nicht korekt? Oder fehlt am parser vielleicht noch etwas?

                  hier der komplette Kopf der XML Datei:
                  <garage xmlns="http://de.intranet.fa.com/XMLSchema/RD" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://de.intranet.fa.com/XMLSchema/RD http://http://de.intranet.fa.com/XMLSchema/RD/gar.xsd">

                  Vielen Dank!

                  Comment


                  • #10
                    Mit XPath selektiert "garage" ein Element mit diesem lokalen Namen in keinem Namensraum. So die Elemente im XML-Dokument aber in einem Namensraum sind, musst du mit XSLT 1.0 im Stylesheet einen Präfix an den Namensraum binden und den Präfix benutzen, um Namen zu qualifizieren
                    Code:
                    <xsl:stylesheet
                      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                      xmlns:rd="http://de.intranet.fa.com/XMLSchema/RD"
                      exclude-result-prefixes="rd"
                      version="1.0">
                    
                      <!-- nun Präfix benutzen --> 
                    
                      <xsl:template match="rd:garage">
                        ...
                      </xsl:template>
                    </xsl:stylesheet>
                    oder mit XSLT 2.0 den xpath-default-namespace setzen:
                    Code:
                    <xsl:stylesheet
                      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                      version="2.0"
                      xpath-default-namespace="http://de.intranet.fa.com/XMLSchema/RD">
                    
                      <xsl:template match="garage">
                        ...
                      </xsl:template>
                    </xsl:stylesheet>
                    Beachte auch, dass man zur Benutzung von XSLT 2.0 einen XSLT 2.0 Prozessor (wie Saxon 9 oder wie AltovaXML Tools) braucht, es reicht nicht, nur das version-Attribut zu ändern.

                    Comment


                    • #11
                      danke

                      Hallo Martin,

                      ich vermute, genau das war von Anfang an mein Problem gewesen und ich habe nur an der falschen Stelle gesucht.

                      Kann das leider später erst testen, aber das hört sich gut an!

                      Vielen Dank für die Mühe!

                      Grüße
                      Alex

                      Comment

                      Working...
                      X