سؤال

أقوم بإجراء بحث واستبدال على حرف تغذية السطر (
) واستبدالها بعلامات إغلاق الفقرة وفتح الفقرة باستخدام الكود التالي:

<xsl:template match="/STORIES/STORY">   
    <component>
        <xsl:if test="boolean(ARTICLEBODY)">
            <p>
                <xsl:call-template name="replace-text">
                        <xsl:with-param name="text" select="ARTICLEBODY"  />
                        <xsl:with-param name="replace" select="'&#10;'" />
                        <xsl:with-param name="by" select="'&lt;/p&gt;&lt;p&gt;'" />
                </xsl:call-template>
            </p>
        </xsl:if>
    </component>
</xsl:template>

<xsl:template name="replace-text">
   <xsl:param name="text"/>
   <xsl:param name="replace" />
   <xsl:param name="by"  />

   <xsl:choose>
   <xsl:when test="contains($text, $replace)">
      <xsl:value-of select="substring-before($text, $replace)"/>
      <xsl:value-of select="$by" disable-output-escaping="yes"/>
      <xsl:call-template name="replace-text">
         <xsl:with-param name="text" select="substring-after($text, $replace)"/>
         <xsl:with-param name="replace" select="$replace" />
         <xsl:with-param name="by" select="$by" />
      </xsl:call-template>
   </xsl:when>
   <xsl:otherwise>
      <xsl:value-of select="$text"/>
   </xsl:otherwise>
   </xsl:choose>
</xsl:template>

يعمل هذا بشكل مثالي تقريبًا، باستثناء أنني أحتاج إليه حقًا لإزالة خلاصات الأسطر حيث تميل الفقرات إلى الفصل بمقدار 2 أو أكثر مما يؤدي إلى </p><p></p><p>.

هل من الممكن الحصول عليه بحيث يستبدل هذا مرة واحدة فقط لكل فقرة؟

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

المحلول

disable-output-escaping ليس شرًا في حد ذاته، ولكن هناك حالات قليلة فقط حيث يجب عليك استخدامه وهذه ليست واحدة منها.في XSLT، أنت تعمل مع الأشجار، وليس سلسلة العلامات.إليك حل XSTL 1.0:

<xsl:template match="/STORIES/STORY">
  <component>
    <xsl:if test="ARTICLEBODY">
      <xsl:call-template name="wrap-text">
        <xsl:with-param name="text" select="ARTICLEBODY"/>
        <xsl:with-param name="delimiter" select="'&#10;'"/>
        <xsl:with-param name="element" select="'p'"/>
      </xsl:call-template>
    </xsl:if>
  </component>
</xsl:template>

<xsl:template name="wrap-text">
  <xsl:param name="text"/>
  <xsl:param name="delimiter"/>
  <xsl:param name="element"/>

  <xsl:choose>
    <xsl:when test="contains($text, $delimiter)">
      <xsl:variable name="t" select="substring-before($text, $delimiter)"/>
      <xsl:if test="normalize-space($t)">
        <xsl:element name="{$element}">
        <xsl:value-of select="$t"/>  
      </xsl:element>
      </xsl:if>        
      <xsl:call-template name="wrap-text">
        <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
        <xsl:with-param name="delimiter" select="$delimiter"/>
        <xsl:with-param name="element" select="$element"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:if test="normalize-space($text)">
        <xsl:element name="{$element}">
          <xsl:value-of select="$text"/>  
        </xsl:element>
      </xsl:if>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

نصائح أخرى

جرب هذا (XSLT 2.0):

    <xsl:template match="/STORIES/STORY">
        <component>
            <xsl:if test="boolean(ARTICLEBODY)">
                <xsl:call-template name="insert_paras">
                    <xsl:with-param name="text" select="ARTICLEBODY/text()"/>
                </xsl:call-template>
            </xsl:if>
        </component>
    </xsl:template>

    <xsl:template name="insert_paras">
        <xsl:param name="text" />

        <xsl:variable name="regex">
            <xsl:text>&#10;(&#10;|\s)*</xsl:text>
        </xsl:variable>
        <xsl:variable name="tokenized-text" select="tokenize($text, $regex)"/>

        <xsl:for-each select="$tokenized-text">
            <p>
                <xsl:value-of select="."/>
            </p>
        </xsl:for-each>
    </xsl:template>

إنها فكرة سيئة عمومًا استخدام السلاسل الحرفية لوضع علامات XML، حيث لا يمكنك ضمان توازن النتائج.

نظرًا لوظائف XPath التي تتصل بها والتي لا أتذكر أنني كنت أستمتع بها في عملي على MSXSL، يبدو أنك تستخدم معالجًا متوافقًا مع XPath 2.

إذا كان الأمر كذلك، ألا يحتوي XPath 2 على وظيفة استبدال (سلسلة، نمط، استبدال) تأخذ التعبير العادي كمعلمة ثانية؟

<xsl:value-of 
    select="replace(string(.), '&#10;(\s|&#10;)*', '&lt;/p&gt;&lt;p&gt;')" />

قد يكون من المفيد الحصول على بعض نماذج إدخالات Xml ومعرفة المعالج الذي تخطط لاستخدامه.

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

<xsl:when test="contains($text, $replace)">
  <xsl:variable name="prefix" select="substring-before($text, $replace)" />
  <xsl:choose>
    <xsl:when test="normalize-string($prefix)!=''">
      <xsl:value-of select="$prefix"/>
      <xsl:value-of select="$by" disable-output-escaping="yes"/>
    </xsl:when>
  </xsl:choose>
  <xsl:call-template name="replace-text">
     <xsl:with-param name="text" select="substring-after($text, $replace)"/>
     <xsl:with-param name="replace" select="$replace" />
     <xsl:with-param name="by" select="$by" />
  </xsl:call-template>

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