Frage

ich habe ein Problem versucht, mit einer XSL-Datei mit dem XslCompiledTransform in CLR4.0 zu sortieren. Hier ist meine XML-Beispieldatei (Hinweis: Es gibt einen Raum nach dem zweiten <foo> Elemente):

<?xml version="1.0" encoding="utf-8"?>
<reflection> 
  <apis>
    <api id="A">
      <foos>
        <foo/>
      </foos>
    </api>
    <api id="B">
      <foos>
        <foo/> 
      </foos>
    </api>     
  </apis>
</reflection>

Wenn ich installieren Sie das folgende XSL-Datei:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">
  <xsl:template match="/">
    <html>
      <body>
        <table>
          <xsl:apply-templates select="/reflection/apis/api">
                        <xsl:sort select="@id" />
                    </xsl:apply-templates>          
        </table>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="api">
    <tr>
      <td>
        <xsl:value-of select="@id" />
      </td>
    </tr>
  </xsl:template>
</xsl:stylesheet>

ich folgendes Ergebnis:

<html>
  <body>
    <table>
      <tr>
        <td>B</td>
      </tr>
      <tr>
        <td>A</td>
      </tr>
    </table>
  </body>
</html>

Allerdings, wenn ich den Raum nach dem zweiten <foo> Elemente entfernen, wird die resultierende Datei korrekt sortiert. Dies scheint, wie es ist wahrscheinlich ein Fehler in den XslCompiledTransform, aber ich habe gehofft, jemand könnte eine Abhilfe hat.

Edit: Wenn jemand Schwierigkeiten hat, es wiedergibt, hier ist der Code verwende ich:

XslCompiledTransform xslt = new XslCompiledTransform();
XsltSettings transformSettings = new XsltSettings(true, true);
xslt.Load("CreateVSToc.xsl", transformSettings, new XmlUrlResolver());

XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.IgnoreWhitespace = true;
Stream readStream = File.Open("reflection.xml", FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
using (XmlReader reader = XmlReader.Create(readStream, readerSettings))
{
    Stream outputStream = File.Open("toc.xml", FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete);
    using (XmlWriter writer = XmlWriter.Create(outputStream, xslt.OutputSettings))
    {

        XsltArgumentList arguments = new XsltArgumentList();
        xslt.Transform(reader, arguments, writer);
    }
}
War es hilfreich?

Lösung 4

@Russ Ferri, vielen Dank für Ihre Antwort. Es wies mich in die richtige Richtung. Es scheint, die Fehler in der XslCompiledTransform ist, dass, wenn Sie durch ein Attribut eines Elements sortieren wollen, es sortiert tatsächlich durch den Wert des ersten Kindes Element dieses Elements. So wie Russ wies darauf hin, dies Art richtig mit meinem ursprünglichen Transformationsdatei:

<reflection>
  <apis>
    <api id="C">
      <id>C</id>
      <foos>
        <foo/>
      </foos>
    </api>
    <api id="B">
      <id>B</id>
      <foos>
        <foo/>
      </foos>
    </api>
  </apis>
</reflection>

Aber so wird dies:

<reflection>
  <apis>
    <api id="C">
      <anyElementName>C</anyElementName>
      <foos>
        <foo/>
      </foos>
    </api>
    <api id="B">
      <anyElementName>B</anyElementName>
      <foos>
        <foo/>
      </foos>
    </api>
  </apis>
</reflection>

In der Tat ist der Attributname vollständig ignoriert, also wenn ich das auf so etwas wie diese Transformation ausführen:

<reflection>
  <apis>
    <api id="C">
      <anyElementName>Z</anyElementName>
      <foos>
        <foo/>
      </foos>
    </api>
    <api id="A">
      <anyElementName>Y</anyElementName>
      <foos>
        <foo/>
      </foos>
    </api>
    <api id="B">
      <anyElementName>X</anyElementName>
      <foos>
        <foo/>
      </foos>
    </api>
  </apis>
</reflection>

Das Ergebnis sieht wie folgt aus:

<html>
  <body>
    <table>
      <tr>
        <td>B</td>
      </tr>
      <tr>
        <td>A</td>
      </tr>
      <tr>
        <td>C</td>
      </tr>
    </table>
  </body>
</html>

Welche ist die korrekte Sortierung ist, wenn man von den <anyElementName> Elementen Sortierung wurde

Andere Tipps

Misstrauisch, wenn die XML für jedes api Element der folgenden geändert wird, wird das Ergebnis sortiert wie erwartet:

<api id="apiId">
   <id>apiId</id>
   <foos>
      <foo />
   </foo>       
</api>

Außerdem, wenn a) die XML für jedes api Element modifiziert wird vollständig das id Attribut entfernen

<api>
   <id>apiId</id>
   <foos>
      <foo />
   </foo>       
</api>

und b) nur die zweiten Verweis auf @id in der XSL-Datei auf id geändert wird, wird das Ergebnis noch alphabetisch sortiert werden!


Es ist möglich, dass der XslCompiledTransform auf einem Kind-Element namens id anstelle einem Attribut namens id zu sortieren versucht, oder dies nur pures Glück sein könnte. So oder so, habe ich überprüft sie bereit ist, richtig auf ein Kind-Element namens id zu sortieren.

In diesem Sinne kann ich von zwei Lösungen denken, aber beide erfordern, dass Sie ein gewisses Maß an Kontrolle über den Transformationsprozess haben.

Ansatz 1: Sie sind in der Lage, die XML zu ändern

Ändern Sie den Prozess der ursprünglichen XML-Schreiben der id angeben als das erste Element durch ein api Element enthalten. Dann die XSL aktualisieren Verweise auf @id mit id zu ersetzen.

Ansatz 2: Sie sind in der Lage, die XML-Vorverarbeitung vor der Anwendung Ihres XSL

Verwenden Sie eine XSL-Transformation den Wert des id Attribut in ein untergeordnetes Element von api zu bewegen, dann die gleiche XSL anwenden, wie Sie es in Ansatz 1 , um die Zwischen-XML-Dokument. Die Umwandlung des Dokuments zweimal wäre natürlich weniger wünschenswert, wenn große XML-Dateien verarbeiten.

Das folgende XSL werden Sie von der ursprünglichen XML die XML-Zwischen erhalten:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">  
   <!-- recursively copy each element (including root) -->
   <xsl:template match="*|/">
      <xsl:copy>      
         <!-- xsl:copy ignores attributes, copy those as well -->
         <xsl:copy-of select="@*"/>      
         <!-- continue to deep copy the element -->
         <xsl:apply-templates />      
      </xsl:copy>
   </xsl:template>    
   <!-- for api elements, move the id attribute into an element -->
   <xsl:template match="api">
      <api>
         <id>
            <xsl:value-of select="@id"/>
         </id>      
         <!-- continue deep copy of api element contents -->
         <xsl:apply-templates />
      </api>
   </xsl:template>   
</xsl:stylesheet>

Ich hoffe, das hilft!

es funktioniert, wenn Änderung der sytyle Blatt Version '1.0' von etwas> = 2.0

Ich habe nicht versucht, das Problem zu reproduzieren, und ich habe nichts offensichtlich falsch mit Ihrem XSL sehen. Hier ist, was würde ich erforschen, um zu sehen, ob es Ihr Problem oder ein Fehler in dem XSL-Engine versuchen, den Raum nach <foo> und Änderung id „A“ bis „C“ zu entfernen. Haben Sie die Ausgabe in der Reihenfolge „B“, „C“ erhalten? Mit anderen Worten, stellen Sie sicher, dass es von id tatsächlich Sortierung wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top