2017-03-15 20 views
1

Ich versuche, Vorgänger-Geschwister und folgende Geschwister mit einer Teilmenge von Datensätzen mit einer Sortierung auf ihnen zu verwenden. Das Problem, dass die vorangehend/folgende bringt Werte aus der ursprünglichen XML Reihenfolge zurück:mit Vorgänger-Geschwister mit mit xsl: sort

<Salaries> 
    <Salary> 
     <Base>1000</Base> 
     <CreatedDate xmlns:d7p1="http://schemas.datacontract.org/2004/07/System"> 
      <d7p1:DateTime>2016-01-09T14:38:54.8440764Z</d7p1:DateTime> 
      <d7p1:OffsetMinutes>0</d7p1:OffsetMinutes> 
     </CreatedDate> 
    </Salary> 
    <Salary> 
     <Base>2000</Base> 
     <CreatedDate xmlns:d7p1="http://schemas.datacontract.org/2004/07/System"> 
      <d7p1:DateTime>2015-01-09T14:38:54.8440764Z</d7p1:DateTime> 
      <d7p1:OffsetMinutes>0</d7p1:OffsetMinutes> 
     </CreatedDate> 
    </Salary> 
    <Salary> 
     <Base>3000</Base> 
     <CreatedDate xmlns:d7p1="http://schemas.datacontract.org/2004/07/System"> 
      <d7p1:DateTime>2017-01-09T14:38:54.8440764Z</d7p1:DateTime> 
      <d7p1:OffsetMinutes>0</d7p1:OffsetMinutes> 
     </CreatedDate> 
    </Salary> 
</Salaries> 

Wenn ich eine Art unter A für-jedes (Gehalt/Gehalt) mit dem AC# Funktion verwenden, um Offset Minuten in ein Datum hinzu und Zum Beispiel in eine lange Zahl umwandeln (z. B. 201701010000) (um die Manipulation in xslt einfacher zu machen).

<xsl:sort select="number(cs:Convertdatetolong(cs:AddOffsetMinutes(substring(p:CreatedDate/d5p1:DateTime,1,19),p:CreatedDate/d5p1:OffsetMinutes)))" order="ascending"/> 

Die Sortierung funktioniert perfekt und ich bekomme die Datensätze aus in der folgenden Reihenfolge:

Das Problem kommt, wenn ich vorhergehenden verwenden -sibling/vorhergehende (und folgende). Ich würde erwarten, dass der erste Datensatz (2000) keinen vorhergehenden Datensatz hat und der letzte Datensatz (3000) keine Folge hat. Allerdings , wenn ich die Verwendung vorangehenden/nachfolgenden ich den bisherigen Rekord und den nächsten Datensatz aus dem ursprünglichen XML erhalten:

  • 2000 (vorhergehenden - 1000/folgenden - 3000)
  • 1000 (vor -/folgenden - 2000
  • )
  • 3000 (vor - 2000/folgenden -)

ich gegen den bisherigen Rekord (in der sortierten Reihenfolge vergleichen können mag) und die aktuelle Datensatz (in der sortierten Reihenfolge):

  • 2000 (vorhergehend -/folgenden - 1000)
  • 1000 (vorhergehenden - 2000/folgende 3000)
  • 3000 (vorhergehende - 1000/folgenden -)

Ich habe versucht preceding-sibling und vor

<xsl:value-of select="preceding::p:Salary[1]/p:Base"/> 
<xsl:value-of select="preceding-sibling::p:Salary[1]/p:Base"/> 
<xsl:value-of select="preceding::p:Salary[position()=1]/p:Base"/> 

(das Gehalt in einem anderen Namespace (p) ist das wirklich möglich oder muss ich Variablen verwenden, um den vorherigen Rekord da sparen ta gegen?

Alle Ideen dankbar erhalten. Ich benutze xslt 1.0

Antwort

1

Obwohl XSLT/XPath oft von einer "Sequenz von Knoten" spricht, ist es tatsächlich genauer, sie als eine "Sequenz von Knotenreferenzen" zu betrachten - weil zum Beispiel derselbe Knoten mehrmals in der Sequenz.Wenn Sie eine Folge von Knotenreferenzen sortieren, ändern Sie die einzelnen Knoten in keiner Weise, Sie ändern nur die Reihenfolge. Das bedeutet, dass die Knoten immer noch in ihrem ursprünglichen Baum genau dort sind, wo sie vorher waren, und ihre Eltern, Geschwister und Nachkommen genau so sind wie zuvor.

Was Sie wollen, ist nicht die vorhergehenden und folgenden Geschwister des Knotens, aber die Knoten, die vor und nach ihm in der sortierten Reihenfolge kommen, was eine ganz andere Sache ist.

Eine Möglichkeit, dies zu tun ist, einen neuen Baum zu konstruieren Kopien des ursprünglichen Knoten enthält, die Sie zum Beispiel erhalten, wenn Sie das tun

<xsl:variable name="x"> 
    <xsl:for-each ...> 
    <xsl:sort ...> 
     <xsl:copy-of select="."/> 

Die Geschwisterbeziehungen der kopierten Knoten werden dann die reflektieren sortierte Reihenfolge. Es gibt das kleinere Problem, dass in XSLT 1.0 $ x ein Ergebnisbaumfragment ist, so dass Sie es mithilfe der Funktion exslt: node-set() in einen Knotensatz konvertieren müssen.

Tatsächlich ist dies in XSLT 1.0 wahrscheinlich die einzige Möglichkeit, da das XSLT 1.0-Datenmodell nur Knotensätze, keine Sequenzen hat, was bedeutet, dass es keine Möglichkeit gibt, eine Sequenz von Knoten in anderen als Dokumentenbestellung. Das 2.0 Modell hat viel mehr Flexibilität und Power. Aktualisieren Sie, wenn Sie können - XSLT 1.0 nähert sich 20 Jahren.

+0

Danke. Ich habe es geschafft, die Werte und Daten in eine Knotenmenge zu setzen, in der Reihenfolge, in der ich sie haben möchte. Ich kämpfe darum, sie in einem for-each zu umkreisen: scheint nicht zu funktionieren – Itsallgonepearshaped

+0

Ah, ich musste den gleichen Namensraum verwenden. Dah. msxsl: Knotenmenge ($ SAL) // p: Gehalt – Itsallgonepearshaped

1

Die preceding-sibling Achse erhält die vorhergehenden Geschwister des Kontextknotens in der Reihenfolge des Dokuments.

Um auf die vorhergehenden Geschwister eines Knotens nach dem Sortieren zu verweisen, müssen Sie zuerst die sortierten Knoten in einer Variablen speichern und in XSLT 1.0 die Variable in eine Knotenmenge konvertieren.

0

Danke an Michael für die Antwort. Posted hier für die Vollständigkeit. Kompliziert wegen der im xml verwendeten Namensräume:

<!-- Puts the whole of the Salary Node into a variable--> 
    <xsl:variable name="SALARY" > 
    <xsl:copy-of select="p:Salaries" /> 
    </xsl:variable> 

    <!-- Puts the the required key data into a node-set with the correct sort applied--> 
    <xsl:variable name="SAL"> 
    <xsl:for-each select="msxsl:node-set($SALARY)//p:Salary"> 
     <xsl:sort select="number(cs:Convertdatetolong(cs:AddOffsetMinutes(substring(p:CreatedDate/d5p1:DateTime,1,19),p:CreatedDate/d5p1:OffsetMinutes)))" order="ascending"/> 
     <xsl:copy-of select="." /> 
    </xsl:for-each> 
    </xsl:variable> 

<!-- Quick Output--> 
    <xsl:for-each select="msxsl:node-set($SAL)//p:Salary"> 
    <xsl:text>Sa:</xsl:text> 
    <xsl:value-of select="position()" /> 
    <xsl:text>Preceding:</xsl:text> 
    <xsl:value-of select="preceding-sibling::p:Salary[1]/p:Base"/> 
    <xsl:value-of select="$newline" /> 
    <xsl:text>Current:</xsl:text> 
    <xsl:value-of select="p:Base"/> 
    <xsl:value-of select="$newline" /> 
    <xsl:text>Following:</xsl:text> 
    <xsl:value-of select="following-sibling::p:Salary[1]/p:Base"/> 
    <xsl:value-of select="$newline"/> 
    </xsl:for-each>