سؤال

أحاول إجراء تحويل على مستند XML. يمكن أن يؤدي تحويل XML الخاص بي إلى نوعين مختلفين من العناصر الأساسية اعتمادًا على قيمة عنصر معين:

<xsl:template match="/">
  <xsl:choose>
    <xsl:when test="/databean/data[@id='pkhfeed']/value/text()='200'">
      <xsl:call-template name="StructureA">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="StructureB">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

ثم يتم إنشاء الهيكل أو الهيكل بمساحات الأسماء الخاصة بهم والخطط الخاصة بهم:

<StructureA xmlns="http://...">

تشترك Structurea & B في بعض العناصر الشائعة بحيث يتم تعريفها في ملف منفصل يسمى "XMLCommon.xslt" التي يتضمن كلا الهيكلين قوالب من. لا يحتوي ملف XMLCommon هذا على مساحة اسم افتراضية محددة كما أريد أن تكون قابلة للاستخدام من مساحة الاسم المحددة في الهيكل أو الهيكل. ولكن عندما أقوم بتشغيل التحويل الخاص بي ، فإن أي قوالب يتم سحبها من الملف المشترك تؤدي إلى سمات XMLNS فارغة:

<StructureA xmlns="http://...">
  <SharedElement xmlns="">Something</SharedElement>
</StructureA>

عند التحقق من التحقق ، يتم استخدام مساحة الاسم الفارغة بدلاً من الوالد الصحيح. هل يعرف أي شخص كيف يمكنني إيقاف القوالب الخاصة بي في ملفي المشترك من إضافة سمات XMLNS الفارغة؟

إليك مقتطف من الملف المشترك:

<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template name="ControlledListStructure">
    <xsl:param name="xmlElem" />
    <xsl:param name="structure" />

    <xsl:element name="{$xmlElem}">
      <!-- Blah blah blah -->
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>
هل كانت مفيدة؟

المحلول

الشيء الرئيسي الذي يجب إدراكه هو أن ورقة الأنماط الخاصة بك تملي اسم كل عنصر تضيفه إلى شجرة النتائج. يحتوي اسم العنصر على جزأين: الاسم المحلي ومساحة الاسم URI. في الكود الخاص بك أعلاه ، يمكنك توفير الاسم المحلي (قيمة $xmlElem) ، لكنك لا تحدد مساحة المساحة URI ، مما يعني أنه سيؤدي إلى الافتراضي للسلسلة الفارغة. (في الواقع ، يأخذ مساحة الاسم الافتراضية لوحدة ورقة الأنماط هذه ؛ نظرًا لأنه لا يوجد شيء ، فهي السلسلة الفارغة.) وبعبارة أخرى ، سيكون العنصر ليس في مساحة الاسم. عند تسلسل المستند ، يجب أن يتضمن معالج XSLT xmlns="" Un-Declarations وذلك لإلغاء مساحة الاسم الافتراضية التي تظهر في الأعلى. خلاف ذلك ، فإن العنصر سيأخذ مساحة الاسم ، وهو ما تمليه ورقة الأنماط. ستكون الطريقة الأقل تدخلاً لإصلاح هذا لإضافة معلمة أخرى (على سبيل المثال $namespaceURI) ، تمامًا كما لديك $xmlElem. ثم تكتب:

<xsl:element name="{$xmlElem}" namespace="{$namespaceURI}">

الآن ، سوف يأخذ العنصر الناتج أي مساحة اسم تخبرها بالتولي (والتي سيكون لها تأثير على إزالة مساحة الاسم الافتراضية هذه).

لابد أن ذلك قد أجاب سؤالك. أقدم ما يلي مواد مكافأة مجانية. ؛-)

يجب عليك إزالة text() اختبار العقدة في مقارنة القيمة الخاصة بك. نادراً ما تحتاج إلى مقارنة قيم العقد النصية مباشرة. بدلاً من ذلك ، يمكنك فقط مقارنة قيمة السلسلة للعنصر نفسه (والتي يتم تعريفها على أنها تسلسل القيم الخيطية لجميع عقد النص النسل). هذا سيبدو هكذا:

<xsl:when test="/databean/data[@id='pkhfeed']/value = '200'">

ميزة القيام بذلك بهذه الطريقة هي أن الكود لن ينكسر إذا كان هناك تعليق يختبئ هناك:

<value>2<!--test-->00</value>

في هذه الحالة ، هناك عقدان نصين ("2" و "00"). سوف يفشل الاختبار الأصلي الخاص بك ، لأنه يتحقق لمعرفة ما إذا كان أي منها يساوي "200". ليس من المحتمل جدًا أن يحدث في هذه الحالة ، ولكن على أي حال ، فإن اختبار القيمة الخيطية للعنصر (على عكس أطفال العقدة النصية) هو ممارسة جيدة عندما تكون هذه نيتك.

أخيرًا ، أشجعك على معرفة قواعد القالب وسياق XPath. أنا أميل إلى تجنب <xsl:choose>, <xsl:call-template>, ، و <xsl:with-param> متى أمكن. لسبب واحد ، يمكن أن تساعدك قواعد القالب على تجنب الكثير من الأجزاء القبيحة والمتطورة من XSLT.

<xsl:template match="/databean[data[@id='pkhfeed']/value = '200']" priority="1">
  <StructureA xmlns="http://...">
    ...
  </StructureA>
</xsl:template>

<xsl:template match="/databean">
  <StructureB xmlns="http://...">
    ...
  </StructureB>
</xsl:template>

حتى لو واصلت استخدام <xsl:call-template>, ، لا يجب أن تضطر إلى تمرير ذلك $structure المعلمة ، لأن العقدة الحالية ستبقى دون تغيير في القالب المسمى. يمكنك الوصول //databean (أو /databean, ، وهو ما أظن أنه ما تعنيه) بنفس السهولة من داخل أي من StructureA أو StructureB القوالب ، لأن العقدة الحالية ستظل "/" (عقدة المستند).

إذا كنت مهتمًا بمعرفة المزيد حول نموذج المعالجة الأساسي لـ XSLT ، وأقوى ميزاته (قواعد القالب) ، فإنني أشجعك على التحقق "كيف يعمل XSLT", ، الفصل الحر المجاني من بلدي XSLT 1.0 مرجع الجيب.

آمل أن يكون هذا مفيدًا لك ، حتى لو كان أكثر مما تتفاوض عليه!

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