سؤال

أواجه مشكلة في محاولة الفرز مع ملف XSL باستخدام XSLCompileDTransform في CLR4.0. إليكم ملف عينة XML (ملاحظة: هناك مساحة بعد الثانية <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>

ومع ذلك ، إذا قمت بإزالة المساحة بعد الثانية <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

Russ Ferri ، شكرًا على إجابتك. وجهت لي في الاتجاه الصحيح. يبدو أن الخلل في 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> عناصر

نصائح أخرى

بشكل مثير للريبة ، إذا كان XML لكل منهما api يتم تعديل العنصر إلى ما يلي ، سيتم فرز النتيجة كما هو متوقع:

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

علاوة على ذلك ، إذا أ) XML لكل منهما api يتم تعديل العنصر لإزالة id تنسب بالكامل

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

و ب) فقط ثانيا إشارة إلى @id في ملف XSL يتم تغييره إلى id, ، ستظل النتيجة مرتبة أبجديًا!


من الممكن أن XslCompiledTransform تحاول الفرز على عنصر الطفل المسمى id بدلا من سمة اسمها id, أو هذا يمكن أن يكون مجرد حظ غبي. في كلتا الحالتين ، قمت بالتحقق من أنه على استعداد للفرز بشكل صحيح على عنصر الطفل المسمى id.

مع وضع ذلك في الاعتبار ، يمكنني التفكير في حلتين ، لكن كلاهما يتطلب أن يكون لديك مستوى من التحكم في عملية التحويل.

النهج 1: أنت قادر على تغيير XML

قم بتغيير العملية كتابة XML الأصلي لتحديد id كما العنصر الأول الموجود بواسطة api عنصر. ثم قم بتحديث XSL لاستبدال المراجع إلى @id مع id.

النهج 2: أنت قادر على تشغيل XML مسبقًا قبل تطبيق XSL الخاص بك

استخدم تحويل XSL لتحريك قيمة id تنسب إلى عنصر طفل api, ، ثم ضع نفس XSL كما تفعل النهج 1 إلى وثيقة XML الوسيطة. من الواضح أن تحويل المستند مرتين سيكون أقل استحسانًا عند معالجة ملفات XML الكبيرة.

سوف تحصل عليك 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>

آمل أن يساعد هذا!

إنه يعمل إذا قام بتغيير نسخة Sytyle إلى "1.0" من أي شيء> = 2.0

لم أحاول إعادة إنتاج المشكلة ، ولا أرى أي شيء خطأ بوضوح في XSL. إليك ما سأستكشفه لمعرفة ما إذا كانت مشكلتك أو خطأ في محرك XSL: حاول إزالة المساحة بعد <foo> وتغيير معرف "A" إلى "C". هل تحصل على الإخراج بالترتيب "B" ، "C"؟ وبعبارة أخرى ، تأكد من أنه في الواقع الفرز حسب المعرف.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top