(XSLT 1.0) كيفية استبدال المساحة ببعض السلسلة من جميع قيم النص في XML؟

StackOverflow https://stackoverflow.com/questions/2318118

  •  22-09-2019
  •  | 
  •  

سؤال

تعديل: بدأت باستبدال الأحرف وانتهى بي الأمر باكتشاف بدائل السلسلة بمساعدة ديميتر نوفاتشيوف و رولاند بومان

أعتقد أن رموز العينة كافية لشرح المتطلبات ..

هذه هي العينة XML:

<root>
  <node1>text node</node1>
  <node2>space between the text</node2>
  <node3> has to be replaced with $</node3>
</root>

هذا هو الإخراج الذي أتوقعه:

<root>
  <node1>text$node</node1>
  <node2>space$between$the$text</node2>
  <node3>$has$to$be$replaced$with$$</node3>
</root>

لقد حاولت كتابة رمز XSLT الذي لا يعرض الإخراج المطلوب ..
هذا هو الرمز:

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
  <xsl:template match="text()[.!='']">
    <xsl:call-template name="rep_space">
      <xsl:with-param name="text" select="."/>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="rep_space">
    <xsl:param name="text"/>
    <xsl:variable name="temp" select="'&#x36;'"/> 
    <xsl:choose>
      <xsl:when test="contains(text,'&#x32;')">
        <xsl:call-template name="rep_space">
          <xsl:with-param name="text" select="concat((concat(substring-before(text,' '),temp)),substring-after(text,' '))"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

Translate (. ، '' ، '$') تعمل .. ولكن ليس إلى المدى المرضي .. أسئلتي هي .. ماذا لو كانت سلسلة بدلاً من الحرف؟ أعني ، لنفترض أنني أقصد استبدال "" ٪ 20 "؟ وحالة أخرى ، ماذا لو لم يكن إدخال XML "طباعة جميلة XML" ، ثم يتم استبدال جميع المساحة التي تظهر في XML بـ "$" ..

طباعة جميلة XML هو الملف الذي يحتوي على مسافة بادئة ، (عادةً ما يكون لديك إدخال XMLs هذا) على سبيل المثال:

عقدة أخرى هذا هو @ المستوى الأدنى

يمكنك ملاحظة ، هناك لا "أحرف الفضاء" قبل <new> <test> العقد ولكنها في الواقع بادئة بشكل صحيح ، (مع Altova Xmlspy يمكننا إعطاء أمر بسيط في قائمة التحرير .. لجعل أي ملفات XML إلى "طباعة جميلة XML") ..

حيث كما في المثال أدناه ..

<new>
  <test>one more node</test>
   <test2>
    <child>this is @ lower level</child>
   </test2>
</new>

هناك شوائب الفضاء قبل كل علامات البدء .. <child> تحتوي العلامة على مسافات أكثر من <test2> عقدة ..

مع العينة الثانية XML .. يتم استبدال جميع chars المساحة ""%20".. وبالتالي سيكون الإخراج ..

<new>
%20%20<test>one%20more%20node</test>
%20%20<test2>
%20%20%20%20<child>this%20is%20@%20lower%20level</child>
%20%20</test2>
</new>

بالتأكيد ليس متوقعًا ..

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

كان ذلك رائعًا للتعلم @dimitre ، @رولاند ، أنا ممتن حقًا وممتن لكم يا رفاق ..

مع تحياتي،
الرضع المحترف.

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

المحلول

حسب رغبة رولاند, ، هنا حل خلفي الذيل:

 <xsl:template name="replace">
  <xsl:param name="ptext"/>
  <xsl:param name="ppattern"/>
  <xsl:param name="preplacement"/>

  <xsl:choose>
     <xsl:when test="not(contains($ptext, $ppattern))">
      <xsl:value-of select="$ptext"/>
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="substring-before($ptext, $ppattern)"/>
       <xsl:value-of select="$preplacement"/>
       <xsl:call-template name="replace">
         <xsl:with-param name="ptext"
           select="substring-after($ptext, $ppattern)"/>
         <xsl:with-param name="ppattern" select="$ppattern"/>
         <xsl:with-param name="preplacement" select="$preplacement"/>
       </xsl:call-template>
     </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

لاحظ أن المكالمة العودية هي التعليمات الأخيرة في القالب-هذا ما يجعلها مرهقة. تتيح خاصية كونك-إعادة توصيل الذيل معالج XSLT الذكي (مثل Saxon أو .NET XSLcompileDTransform) لتحسين الكود ، واستبدال العودية بالتكرار البسيط.

لن ينتهي هذا الرمز باستثناء التدفق المكدس حتى عندما يكون "تعشيش" المكالمات هو الملايين ، في حين أن الكود غير المتواصل (والعودية) عادة يعتمد حقًا على مقدار الذاكرة المتاحة).

ماذا لو لم يكن معالج XSLT "ذكيًا بدرجة كافية"؟ هل هناك تقنية أخرى لتجنب مكدس المكالمات العودية العميقة ، والتي تعمل معها كل معالج XSLT؟

اسألني في سؤال منفصل وقد أخبرك :)

نصائح أخرى

تحقق من وظيفة ترجمة XPath:http://www.w3.org/tr/xpath/#function-translate

<xsl:template match="text()">
    <xsl:value-of select="translate(., ' ', '$')"/>
</xsl:template>

إذا لم تكن حرفًا واحدًا ، ولكن سلسلة يجب أن تستبدلها ، فإنها تتطلب المزيد من الجهد ، وتحتاج إلى قالب لاستبدال السلسلة بشكل متكرر:

<xsl:template match="text()[not(../*)]">
    <xsl:call-template name="replace">
        <xsl:with-param name="text" select="."/>
        <xsl:with-param name="search" select="' '"/>
        <xsl:with-param name="replace" select="'%20'"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="replace">
    <xsl:param name="text"/>
    <xsl:param name="search"/>
    <xsl:param name="replace"/>
    <xsl:choose>
        <xsl:when test="contains($text, $search)">
            <xsl:variable name="replace-next">
                <xsl:call-template name="replace">
                    <xsl:with-param name="text" select="substring-after($text, $search)"/>
                    <xsl:with-param name="search" select="$search"/>
                    <xsl:with-param name="replace" select="$replace"/>
                </xsl:call-template>
            </xsl:variable>
            <xsl:value-of 
                select="
                    concat(
                        substring-before($text, $search)
                    ,   $replace
                    ,   $replace-next
                    )
                "
            />
        </xsl:when>
        <xsl:otherwise><xsl:value-of select="$text"/></xsl:otherwise>
    </xsl:choose>
</xsl:template>

تحرير: تم تغيير match = "text ()" to match = "text () [not (..//)] ، بحيث لا يلزم أن يكون الإدخال xml نوعًا من" طباعة جميلة xml ".. (وذلك إلى إزالة بدائل غير مرغوب فيها للمساحة مع سلسلة "٪ 20" في ملف XML)

إن الحل لـ "XML المطبوعة المطبوع" ليس حلًا حقًا.

تخيل وجود وثيقة مثل هذا:

<a>
 <b>
  <c>O M G</c>
  <d>D I Y</d>
 </b>
</a>

الإخراج من الحل المقبول حاليًا (بعد لفه في <xsl:stylesheet> وإضافة قاعدة الهوية هي:

<a>
%20<b>
%20%20<c>O$M$G</c>
%20%20<d>D$I$Y</d>
%20</b>
</a>

الآن ، لماذا لا ينقذ الحل البديل المقترح الموقف؟ كما نرى من المثال أعلاه ، يمكن أن يكون لعنصر أكثر من عنصر طفل يحتوي على العقد النصية ...

ما هو الحل الحقيقي?

لقد فكر المبدعون في XSLT في هذه المشكلة. باستخدام المصطلحات الصحيحة ، نريد أن يتم تجاهل جميع العقد النصية ذات المساحة البيضاء فقط من قبل معالج XSLT ، كما لو لم تكن جزءًا من شجرة المستندات على الإطلاق. هذا يتحقق من قبل <xsl:strip-space> تعليمات.

فقط أضف هذا على المستوى العالمي (كطفل <xsl:stylesheet> وقابلية القراءة ، قبل أي قوالب):

 <xsl:strip-space elements="*"/>

والآن لديك حقًا حل عمل.

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