هو XSL: التسلسل دائما غير فارغ؟
-
11-09-2019 - |
سؤال
أنا لا أفهم الإخراج من هذه الأنماط:
<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/*)" />
سوف أعطيك الإخراج الذي تتوقعه.