سؤال

أنا لا أفهم الإخراج من هذه الأنماط:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:apply-templates select="root/sub"/>
    </xsl:template>

    <xsl:template match="sub">
        <xsl:variable name="seq">
            <xsl:sequence select="*" />
        </xsl:variable>

        <xsl:message>
            <xsl:value-of select="@id" />
            <xsl:text>: </xsl:text>
            <xsl:value-of select="count($seq)" />
        </xsl:message>
    </xsl:template>
</xsl:stylesheet>

عند تطبيقها على XML التالية:

<root>
    <sub id="empty" />
    <sub id="one"><one/></sub>
    <sub id="two"><one/><one/></sub>
    <sub id="three"><one/><one/><one/></sub>
</root>

الإخراج، كتبها xsl:message العنصر، هو:

empty: 1
one: 1
two: 1
three: 1

كنت أتوقع هذا واحد بدلا من ذلك:

empty: 0
one: 1
two: 2
three: 3

لماذا count($seq) دائما العودة 1 في هذه الحالة؟ كيف يمكنك تغيير تعريف المتغير، حتى أتمكن من اختبارها لاحقا للفراغ؟ (بسيط <xsl:variable name='seq' select='*' /> سوف يعود الإجابة المتوقعة، ولكن ليس خيارا ... أريد أن أغير between متغير في هذا القالب, ، واختبرها للفراغ في وقت لاحق).

هل كانت مفيدة؟

المحلول

اسمحوا لي أن أحاول الإجابة على "لماذا" جزء من سؤالك.

إذا كتبت العبارة التالية:

<xsl:variable name="x" select="*" />

المتغير $x يحتوي على تسلسل العقد الطفل العقدة الحالية. ليس هناك عقدة الأصل الضمنية في $x, ، لأنك تستخدم select. وبعد النظر الآن فيما يلي:

<xsl:variable name="x">
    <content />
    <content />
</xsl:variable>

حيث المتغير $x يحتوي على سلسلة من عقدة واحدة: العقدة الأصل content. وبعد هنا، count($x) سوف تعطيك دائما 1. وبعد للحصول على كمية content عناصر، تحتاج إلى حساب أطفال $x عقدة الجذر الضمنية: count($x/content).

كقاعدة عامة، يمكنك تذكر أن: إذا xsl:variable هو نفسه عنصر فارغ مع select السمة، سيتم تعيين مجموعة النتائج للمتغير. كما ترى xsl:variable بدون ال select السمة، يمكنك دائما إنشاء موالدي ضمني مع المتغير، ومحتويات المتغير هي الأطفال تحتها.

الأمر نفسه ينطبق على مثالك مع xsl:sequence كطفل ل xsl:variable. وبعد من خلال وجود غير فارغ xsl:variable يمكنك إنشاء موال ضمني للتسلسل، وهذا هو السبب في أنك تحصل عليه دائما 1 إذا قمت بحسق المتغير نفسه.

إذا كنت بحاجة إلى كليهما: حزمة من العبارات في الداخل xsl:variable, ، ولكن سلوك select السمة، يمكنك حل هذا باستخدام ما يلي:

<xsl:variable name="x" select="$y/*" />

<xsl:variable name="y">
    <xsl:sequence select="foo" />
</xsl:variable>

والتي سوف تسفر الآن المبلغ المتوقع ل count($x), ، ولكن ما إذا كان هذا مفيدا حقا أم لا يجعل رمزك أكثر وضوحا قابلة للجدول.

نصائح أخرى

إنه يعمل كما قد تتوقع إذا قمت بتغيير الإعلان المتغير إلى:

<xsl:variable name="seq" select="*"/>

أو تعلن نوع المتغير باستخدام السمة "ك":

<xsl:variable name="seq" as="item()*">
        <xsl:sequence select="*" />
</xsl:variable>

لا تحدد أي معلومات من النوع غالبا إلى نتائج مفاجئة في XSLT 2.0. إذا كنت تستخدم سكسون، فيمكنك إخراج كيفية تفسير سكسون ورقة الأنماط باستخدام سمة شرح الامتداد:

    <xsl:template match="sub" saxon:explain="yes" xmlns:saxon="http://saxon.sf.net/">
    <xsl:variable name="seq">
        <xsl:sequence select="*" />
    </xsl:variable>

    <xsl:message>
        <xsl:value-of select="@id" />
        <xsl:text>: </xsl:text>
        <xsl:value-of select="count($seq)" />
    </xsl:message>
</xsl:template>

كما ترون، يقوم ساكسون ببناء عقدة مستندات خارج التسلسل:

Optimized expression tree for template at line 6 in :
                    let $seq[refCount=1] as document-node() :=
                      document-constructor
                        child::element()
                    return
                      message

أنت تختار العقد الفرعية، ثم عد كل عقدة - لذلك سيكون دائما 1. تحتاج إلى حساب الأطفال، على سبيل المثال:

<xsl:value-of select="count($seq/*)" />

سوف أعطيك الإخراج الذي تتوقعه.

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