3

CLR4.0 で XslCompiledTransform を使用して XSL ファイルを並べ替えようとすると問題が発生します。これが私のサンプル XML ファイルです (注: 2 番目の<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>

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

次の結果が得られます。

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

ただし、2 番目の要素の後のスペースを削除する<foo>と、結果のファイルは正しく並べ替えられます。これはおそらく XslCompiledTransform のバグのようですが、誰かが回避策を持っていることを願っていました。

編集:誰かがそれを再現するのに問題がある場合は、ここに私が使用しているコードがあります:

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);
    }
}
4

4 に答える 4

2

スタイルシートのバージョンを2.0以上の「1.0」に変更すると機能します

于 2010-12-29T08:33:06.223 に答える
2

api疑わしいことに、各要素の XML を次のように変更すると、結果は期待どおりに並べ替えられます。

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

さらに、a) 各要素の XML を変更して属性を完全apiに削除する場合id

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

b) XSL ファイル内のへの2 番目の参照のみが に変更され、結果は引き続きアルファベット順にソートされます。 @idid


が という名前の属性の代わりにXslCompiledTransformという名前の子要素でソートしようとしている可能性があります。または、これは運が悪かっただけかもしれません。いずれにせよ、という名前の子要素で正しく並べ替えられることを確認しました。 ididid

これを念頭に置いて、2 つの回避策を考えることができますが、どちらも変換プロセスをある程度制御する必要があります。

アプローチ 1: XML を変更することができます

元の XML を記述するプロセスを変更して、id要素に含まれる最初の要素としてを指定しますapi。次に、XSL を更新して への参照を に置き換え@idますid

アプローチ 2: XSL を適用する前に XML を前処理できます。

XSL 変換を使用してid属性の値を の子要素に移動し、アプローチ 1apiと同じ XSL を中間 XML ドキュメントに適用します。大きな XML ファイルを処理する場合、ドキュメントを 2 回変換することは明らかに望ましくありません。

次の XSL は、元の XML から中間 XML に移動します。

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

これが役立つことを願っています!

于 2010-11-10T01:56:46.317 に答える
1

私は問題を再現しようとはしていませんし、XSLに明らかに問題はありません。これが、XSLエンジンの問題なのかバグなのかを調べるために調べます。後のスペースを削除して、<foo>ID「A」を「C」に変更してみてください。「B」、「C」の順に出力されますか?つまり、実際にIDで並べ替えられていることを確認してください。

于 2010-11-10T01:25:45.887 に答える
0

@ラスフェリ、あなたの答えに感謝します。それは私を正しい方向に向けました。XslCompiledTransformのバグは、要素の属性で並べ替えるときに、実際にはその要素の最初の子要素の値で並べ替えることです。したがって、ラスが指摘したように、これは私の元の変換ファイルで正しくソートされます。

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

しかし、これもそうです:

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

実際、属性名は完全に無視されるため、次のようなもので変換を実行すると、次のようになります。

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

結果は次のようになります。

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

<anyElementName>要素で並べ替える場合、これは正しい並べ替えです

于 2010-11-15T18:16:04.460 に答える