XSLT بنية محتوى تعميق
-
22-09-2019 - |
سؤال
بالنظر إلى الهيكل التالي:
<TITEL1>...</TITEL1>
<p>..</p>
<TITEL2>...</TITEL2>
<TITEL3>...</TITEL3>
<TITEL3>...</TITEL3>
<P>...<P>
هل هناك طريقة للوصول إلى هذا:
<TITEL1>
<TITEL>...</TITEL>
<p>...</p>
<TITEL2>
<TITEL>...</TITEL>
<TITEL3>
<TITEL>...</TITEL>
<P>...</P>
</TITEL3>
<TITEL3>
<TITEL>...</TITEL>
<P>...</P>
</TITEL3>
</TITEL2>
</TITEL1>
أو بعبارة أخرى ، هل هناك طريقة للحصول على أغاني أعلى مستوى تميل إلى ارتباطات مستوى أقل وجميع المحتوى الذي يتبعها ، وبالتالي إنشاء بنية متداخلة. يجب أن يذهب محتوى كل علامة Titel1،2 و 3 إلى جديد <TITEL>
-عنصر
المحلول
باستخدام XSLT 2.0 (كما تنفذها Saxon 9 أو AltovaxML Tools) ، يمكنك استخدام XSL: من أجل بدء مجموعة المجموعة ودالة متكررة:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/2010/mf"
exclude-result-prefixes="xsd mf">
<xsl:output indent="yes"/>
<xsl:function name="mf:nest" as="element()*">
<xsl:param name="elements" as="element()*"/>
<xsl:param name="level" as="xsd:integer"/>
<xsl:for-each-group select="$elements" group-starting-with="*[starts-with(local-name(), concat('TITEL', $level))]">
<xsl:choose>
<xsl:when test="self::*[starts-with(local-name(), concat('TITEL', $level))]">
<xsl:element name="TITEL{$level}">
<xsl:apply-templates select="."/>
<xsl:sequence select="mf:nest(current-group() except ., $level + 1)"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="ROOT">
<xsl:sequence select="mf:nest(*, 1)"/>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(local-name(), 'TITEL')]">
<TITEL>
<xsl:apply-templates select="@* | node()"/>
</TITEL>
</xsl:template>
</xsl:stylesheet>
مع تلك الورقة الأنماوية المدخلات
<ROOT>
<TITEL1>Titel 1, 1</TITEL1>
<p>..</p>
<TITEL2>Titel 2, 1</TITEL2>
<TITEL3>Titel 3, 1</TITEL3>
<TITEL3>Titel 3, 2</TITEL3>
<P>...</P>
</ROOT>
يتحول إلى الإخراج
<TITEL1>
<TITEL>Titel 1, 1</TITEL>
<p>..</p>
<TITEL2>
<TITEL>Titel 2, 1</TITEL>
<TITEL3>
<TITEL>Titel 3, 1</TITEL>
</TITEL3>
<TITEL3>
<TITEL>Titel 3, 2</TITEL>
<P>...</P>
</TITEL3>
</TITEL2>
</TITEL1>
نصائح أخرى
لا توجد طريقة متألقة بشكل خاص لفعل ما تريد. من الممكن (على الأرجح) ، ولكنه سيتضمن بعض استعلامات Xpath قبيحة (وبطيئة) باستخدام following-sibling
محور مع المرشحات على preceding-sibling
محور مطابقة للعقدة الحالية.
إذا كان ذلك احتمالًا على الإطلاق ، فإنني أوصي بإنشاء التسلسل الهرمي خارج XSLT (في C#، Java ، إلخ)
إذا اخترت السير في المسار المخيف ، فستتطلع إلى القيام بشيء كهذا (لم يتم اختباره):
<xsl:template match="TITEL1">
<TITEL1>
<xsl:apply-templates
select="following-sibling::(p|TITEL2)[(preceding-sibling::TITEL1)[1]=.]" />
</TITEL1>
</xsl:template>
<xsl:template match="TITEL2">
<TITEL1>
<xsl:apply-templates
select="following-sibling::(p|TITEL3)[(preceding-sibling::TITEL2)[1]=.]" />
</TITEL1>
</xsl:template>
...
هذا مجرد مثال ، ويمكنني بالفعل رؤية مشاكل في المباراة. سيكون الخروج مع استعلام XPath النهائي متورطًا تمامًا ، إذا كان ذلك ممكنًا بالفعل على الإطلاق.
إذا لم تتمكن من استخدام XSLT 2.0 ، فإليك ورقة أنماط XSLT 1.0 التي يجب أن تنتج نفس النتيجة مثل ورقة الأنماط XSLT 2.0 التي نشرتها سابقًا:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="ROOT">
<xsl:apply-templates select="*[1]" mode="nest">
<xsl:with-param name="level" select="1"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[starts-with(local-name(), 'TITEL')]" mode="nest">
<xsl:param name="level"/>
<xsl:choose>
<xsl:when test="$level = substring-after(local-name(), 'TITEL')">
<xsl:element name="TITEL{$level}">
<xsl:apply-templates select="."/>
<xsl:apply-templates select="following-sibling::*[1][not(starts-with(local-name(), concat('TITEL', $level)))]" mode="nest">
<xsl:with-param name="level" select="$level"/>
</xsl:apply-templates>
</xsl:element>
<xsl:apply-templates select="following-sibling::*[starts-with(local-name(), concat('TITEL', $level))][1]" mode="nest">
<xsl:with-param name="level" select="$level"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." mode="nest">
<xsl:with-param name="level" select="$level + 1"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*[not(starts-with(local-name(), 'TITEL'))]" mode="nest">
<xsl:param name="level"/>
<xsl:apply-templates select="."/>
<xsl:apply-templates select="following-sibling::*[1][not(starts-with(local-name(), concat('TITEL', $level)))]" mode="nest">
<xsl:with-param name="level" select="$level"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(local-name(), 'TITEL')]">
<TITEL>
<xsl:apply-templates select="@* | node()"/>
</TITEL>
</xsl:template>
</xsl:stylesheet>