4 Stimmen

XSLT kombiniert mehrere Knoten zu einem einzigen Knoten

<RowSet>
 <Row>
  <Location_Long_Desc>Sydney Office</Location_Long_Desc>
  <Location_Code>SYDNEY</Location_Code>
  <Daypart_Long_Desc>Peak Night</Daypart_Long_Desc>
  <Daypart_Code>PEANIG</Daypart_Code>
  <W_20050703_Dlr>30849.3</W_20050703_Dlr>
  <W_20050703_Spots>9</W_20050703_Spots>
  <W_20050710_Dlr>16.35</W_20050710_Dlr>
  <W_20050710_Spots>19</W_20050710_Spots>
 </Row>
</RowSet>

Also, ich habe diese XML jetzt, was ich brauche, um die W_-Knoten in einen neuen einzelnen Knoten zu konvertieren. Mit diesem XSL

<?xml version="1.0"?>
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="node()">
    <xsl:copy>
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="*">
    <xsl:variable name="tmp" select="local-name()"/>
    <xsl:choose>
      <xsl:when test="starts-with($tmp, 'W_') and ends-with($tmp, '_Dlr')">
    <xsl:if test="text() != ''">
          <xsl:element name="Expenditure">
            <xsl:element name="Period">
              <xsl:value-of select="substring($tmp,3,8)"/>
            </xsl:element>
            <xsl:element name="Value">
              <xsl:apply-templates select="node()"/>
            </xsl:element>
            <xsl:element name="Spots">
              <xsl:apply-templates select="//RowSet/Row/W_20050703_Spots/text()"/>
            </xsl:element>
          </xsl:element>
    </xsl:if>
    </xsl:when>
    <xsl:otherwise>
        <xsl:element name="{$tmp}">
          <xsl:apply-templates select="node()"/>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

Ich kann es fast schaffen, aber ich habe ein paar Probleme.

  1. Ich muss die W_???????? Dlr und W ????????_Spots in einen einzelnen Knotenpunkt, sondern
  2. Ich kann nicht herausfinden, wie man eine Variable in einer xpath-Anweisung verwendet, oder vielleicht liege ich auch meilenweit daneben, wo ich sein sollte.

Auch hier bin ich noch dabei, alles in den Griff zu bekommen, also seid bitte nachsichtig ;-)

TIA

BEARBEITEN: 02/12/2010 12:00

Gut,

Noch eine kleine Frage: Je nach einem Schalter auf Datenbankebene (den ich ganz vergessen habe) kann der Knoten Spots existieren oder nicht.

So muss ich noch ausgeben, obwohl es nicht auf die folgende-Geschwister-Aufruf, wo die folgende-Geschwister ist nicht eine gültige _spots Knoten sollte.

Beispiel:

<RowSet>
 <Row>
  <Location_Long_Desc>Sydney Office</Location_Long_Desc>
  <Location_Code>SYDNEY</Location_Code>
  <Daypart_Long_Desc>Peak Night</Daypart_Long_Desc>
  <Daypart_Code>PEANIG</Daypart_Code>
  <W_20050703_Dlr>30849.3</W_20050703_Dlr>
  <W_20050710_Dlr>16.35</W_20050710_Dlr>
 </Row>
</RowSet>

Nur damit Sie es wissen, ich rufe das alles über ein Oracle-Paket auf

-- get the query context;
v_qryctx := dbms_xmlgen.newcontext(in_sql_query);

dbms_xmlgen.setnullhandling(v_qryctx, 2);
dbms_xmlgen.setrowsettag(v_qryctx, 'RowSet');
dbms_xmlgen.setrowtag(v_qryctx, 'Row');

IF in_export_type = cnst_export_booking
THEN
    dbms_xmlgen.setxslt(v_qryctx, v_booking_export_xsl);

ELSIF in_export_type = cnst_export_expenditure
THEN
    dbms_xmlgen.setxslt(v_qryctx, v_expenditure_export_xsl);

END IF;

5voto

Dimitre Novatchev Punkte 234995

Diese Umwandlung :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match=
 "*[starts-with(name(),'W_')
  and
   substring-after(substring-after(name(),'_'),'_')='Dlr'
  and
   text()
   ]">
  <Expenditure>
    <Period>
      <xsl:value-of select="substring(name(),3,8)"/>
    </Period>
    <Value>
      <xsl:apply-templates/>
    </Value>
      <xsl:apply-templates mode="extract" select=
      "following-sibling::*[1]
        [starts-with(name(),'W_')
       and
        substring-after(substring-after(name(),'_'),'_')='Spots'
         ]
       "/>
  </Expenditure>
 </xsl:template>

 <xsl:template mode="extract" match=
  "*[starts-with(name(),'W_')
  and
   substring-after(substring-after(name(),'_'),'_')='Spots'
    ]
  ">
   <Spots><xsl:value-of select="."/></Spots>
  </xsl:template>

 <xsl:template match=
  "*[starts-with(name(),'W_')
  and
   substring-after(substring-after(name(),'_'),'_')='Spots'
    ]
  "/>
</xsl:stylesheet>

bei Anwendung auf das angegebene XML-Quelldokument :

<RowSet>
 <Row>
  <Location_Long_Desc>Sydney Office</Location_Long_Desc>
  <Location_Code>SYDNEY</Location_Code>
  <Daypart_Long_Desc>Peak Night</Daypart_Long_Desc>
  <Daypart_Code>PEANIG</Daypart_Code>
  <W_20050703_Dlr>30849.3</W_20050703_Dlr>
  <W_20050703_Spots>9</W_20050703_Spots>
  <W_20050710_Dlr>16.35</W_20050710_Dlr>
  <W_20050710_Spots>19</W_20050710_Spots>
 </Row>
</RowSet>

das gewünschte, korrekte Ergebnis liefert :

<RowSet>
   <Row>
      <Location_Long_Desc>Sydney Office</Location_Long_Desc>
      <Location_Code>SYDNEY</Location_Code>
      <Daypart_Long_Desc>Peak Night</Daypart_Long_Desc>
      <Daypart_Code>PEANIG</Daypart_Code>
      <Expenditure>
         <Period>20050703</Period>
         <Value>30849.3</Value>
         <Spots>9</Spots>
      </Expenditure>
      <Expenditure>
         <Period>20050710</Period>
         <Value>16.35</Value>
         <Spots>19</Spots>
      </Expenditure>
   </Row>
</RowSet>

wenn es auf das zweite bereitgestellte XML-Dokument angewendet wird, das der OP in einem Update angefordert hat:

<RowSet>
 <Row>
  <Location_Long_Desc>Sydney Office</Location_Long_Desc>
  <Location_Code>SYDNEY</Location_Code>
  <Daypart_Long_Desc>Peak Night</Daypart_Long_Desc>
  <Daypart_Code>PEANIG</Daypart_Code>
  <W_20050703_Dlr>30849.3</W_20050703_Dlr>
  <W_20050710_Dlr>16.35</W_20050710_Dlr>
  <W_20050710_Spots>19</W_20050710_Spots>
 </Row>
</RowSet>

wieder das gewünschte, richtige Ergebnis (Nein <Spot> Element wird erzeugt, wenn der unmittelbare Geschwisterteil nicht ein W_nnnnnnnn_Spots ) erzeugt:

<RowSet>
   <Row>
      <Location_Long_Desc>Sydney Office</Location_Long_Desc>
      <Location_Code>SYDNEY</Location_Code>
      <Daypart_Long_Desc>Peak Night</Daypart_Long_Desc>
      <Daypart_Code>PEANIG</Daypart_Code>
      <Expenditure>
         <Period>20050703</Period>
         <Value>30849.3</Value>
      </Expenditure>
      <Expenditure>
         <Period>20050710</Period>
         <Value>16.35</Value>
         <Spots>19</Spots>
      </Expenditure>
   </Row>
</RowSet>

Bitte beachten :

  1. Die Anwendung der Identitätsregel um einen beliebigen Knoten "so wie er ist" zu kopieren.

  2. Die Überschreibung der Identitätsvorlage nur für W_nnnnnnnn_Dlr Elemente.

  3. Die Überschreibung der Identitätsvorlage mit einer leeren Vorlage passend zu W_nnnnnnnn_Spots Elemente.

  4. Die Verwendung der Standard-XPath-Funktionen : name() , starts-with() y substring-after()

  5. Die Funktion ends-with() ist nur in XPath 2.0 verfügbar (XSLT 2.0) und wird in dieser XSLT 1.0 Lösung nicht verwendet.

1voto

ndim Punkte 33229

Ich würde mit einer Vorlage beginnen wie

<xsl:template match="Row/*[starts-with(name(), 'W_') and
                           ends-with(name(), '_Dlr')]">

das dem gewünschten Element genauer entsprechen sollte. Wie wählt man die benachbarten <W_${DATE}_Spots> Geschwister-Element... warum nicht das following-sibling XPath-Achse mit der richtigen Zeichenfolge?

<xsl:template match="Row/*[starts-with(local-name(), 'W_') and
                           ends-with(local-name(), '_Dlr')]">
  <xsl:variable name="date" select="substring(local_name(),3,8)"/>
  ...
  <xsl:apply-templates select="following-sibling::*[local-name() ==
                               concat('W_', concat($date, '_Spots'))]"/>
  ...
</xsl:template>

<xsl:template match="Row/*[starts-with(local-name(), 'W_') and
                          ends-with(local-name(), '_Spots')]">
  <xsl:variable name="date" select="substring(local_name(),3,8)"/>
  ...
</xsl:template>

Übrigens sieht das wie eine Endlosschleife aus, die nur darauf wartet, dass etwas passiert:

<xsl:template match="*">
   ...
   <xsl:apply-templates select="node()"/>
   ...
</xsl:template>

Ich bin mir sicher, dass meine Antwort ein paar Fehler enthält, aber sie sollte trotzdem in gewisser Weise hilfreich sein.

1voto

Daniel Haley Punkte 48844

Hier ist eine ähnliche Antwort wie die von Dimitre. Ich hatte sie bereits geschrieben, also dachte ich, ich poste sie einfach...

XSLT (2.0)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="node()|@*">
    <xsl:choose>
      <xsl:when test="starts-with(local-name(), 'W_') and ends-with(local-name(), '_Dlr')">
        <xsl:variable name="period" select="substring(local-name(),3,8)"/>
        <Expenditure>
          <Period><xsl:value-of select="$period"/></Period>
          <Value><xsl:apply-templates/></Value>
          <Spots><xsl:value-of select="following-sibling::*[starts-with(local-name(), 'W_') and ends-with(local-name(),concat($period,'_Spots'))]"/></Spots>
        </Expenditure>
      </xsl:when>
      <xsl:when test="ends-with(local-name(), '_Spots')"/>
      <xsl:otherwise>
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Wenn Sie XSLT 2.0 verwenden (wovon ich ausgehe, da Sie ends-with() ) können Sie verwenden tokenize() um Teile des Namens zu erfassen.

Beispiel:

<xsl:variable name="period" select="tokenize(local-name(),'_')[2]"/>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X