Domanda

Sto avendo un problema cercando di risolvere con un file XSL utilizzando il XslCompiledTransform in CLR4.0. Ecco il mio file XML di esempio (Nota: c'è uno spazio dopo il secondo elemento <foo>):

<?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>

Quando applico il seguente file XSL:

<?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>

ottengo il seguente risultato:

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

Tuttavia, se rimuovere lo spazio dopo il secondo elemento <foo>, il file risultante è ordinato in modo corretto. Questo mi sembra è probabilmente un bug nel XslCompiledTransform, ma speravo che qualcuno potrebbe avere una soluzione.

Edit: Se qualcuno sta avendo problemi a riprodurlo, ecco il codice che sto usando:

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);
    }
}
È stato utile?

Soluzione 4

@Russ Ferri, grazie per la risposta. E mi ha segnalato nella giusta direzione. Sembra che il bug nel XslCompiledTransform è che quando si desidera ordinare da un attributo di un elemento, in realtà ordina in base al valore del primo elemento figlio di quell'elemento. Così come Russ ha sottolineato, questo file di tipo correttamente con il mio originale trasformare:

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

Ma così sarà questo:

<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 realtà, il nome dell'attributo è completamente ignorato, quindi se ho eseguito la trasformazione su qualcosa di simile:

<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>

Gli sguardi risultato come questo:

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

Qual è l'ordinamento corretto se si fosse l'ordinamento per gli elementi <anyElementName>

Altri suggerimenti

Sospettosamente, se il codice XML per ogni elemento api viene modificato per quanto segue, il risultato verrà ordinato come previsto:

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

Inoltre, se a) la XML per ogni elemento api viene modificato per rimuovere l'attributo id interamente

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

e b) solo il secondo riferimento alla @id nel file XSL viene modificato in id, il risultato sarà ancora in ordine alfabetico!


E 'possibile che il XslCompiledTransform sta tentando di ordinare su un elemento figlio di nome id invece di un id attributo denominato, o questo potrebbe essere solo fortuna muto. Ad ogni modo, ho verificato che è disposto a ordinare correttamente su un elemento figlio di nome id.

Con questo in mente, mi viene in mente due soluzioni, ma entrambi richiedono di avere un certo livello di controllo sul processo di trasformazione.

Approccio 1: Siete in grado di modificare il codice XML

Cambia il processo di scrittura del XML originale per specificare la id come il primo elemento contenuto da un elemento api. Quindi aggiornare il XSL per sostituire i riferimenti a @id con id.

Approccio 2: Siete in grado di pre-processo il codice XML prima di applicare il XSL

Usa un trasformazione XSL per spostare il valore dell'attributo id in un elemento figlio di api, quindi applicare lo stesso XSL come si farebbe in Approccio 1 per il documento XML intermedio. Trasformare il documento due volte sarebbe ovviamente meno desiderabile durante l'elaborazione di grandi file XML.

Il seguente XSL ti porterà da XML originale al XML intermedio:

<?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>

Spero che questo aiuta!

funziona se il cambiamento della versione foglio di sytyle a '1.0' di tutto> = 2.0

non ho provato a riprodurre il problema, e non vedere nulla, ovviamente, va con il vostro XSL. Ecco quello che vorrei esplorare per vedere se è il vostro problema o un bug nel motore XSL: provare a rimuovere lo spazio dopo <foo> e cambiare ID "A" a "C". Non si ottiene l'uscita nell'ordine "B", "C"? In altre parole, fare in modo che in realtà è l'ordinamento per id.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top