سؤال

بالنظر إلى الهيكل التالي:

<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>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top