(XSLT ، تحسين الكود) كيفية إخراج العقد التي تشير إلى قيمة الأخوة الأخوة ..؟

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

  •  21-09-2019
  •  | 
  •  

سؤال

أقوم بتحويل XML إلى XML باستخدام XSLT ، الهدف هو قراءة قيمة العلامة <node1>, ، إذا كان فارغًا ، فيجب تعيينه بقيمة <node2>, ، إذا كان ذلك <node2>, ، هو أيضا لاغية ، ثم النص الافتراضي "الافتراضي" يجب تعيين .. لكلا العلامات ..
تعديل: لو <node2>هو لاغ و <node1> ليس .. ثم لا ينبغي للتحديث الرمز <node2> مع 'Default' النص ولكن يجب أن يتحول كما هو ..

هذا هو الاختبار XML الذي أحاوله:

<root>
    <node1></node1>
    <node2></node2>
  <parent>
    <node1>data1</node1>
    <node2></node2>
  </parent>
  <parent>
    <node1></node1>
    <node2>data2</node2>
  </parent>
  <parent>
    <node1>data1</node1>
    <node2>data2</node2>
  </parent>
</root>

وهذا رمز XSLT الذي صممته:

   <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
  <xsl:template name="template1" match="node2[(following-sibling::node1[.='']|preceding-sibling::node1[.=''])]">
    <xsl:choose>
      <xsl:when test=".=''">
        <node1><xsl:text>Default</xsl:text></node1>
        <node2><xsl:text>Default</xsl:text></node2>
      </xsl:when>
      <xsl:otherwise>
        <node1>
          <xsl:value-of select="text()"/>
        </node1>
        <xsl:copy>
          <xsl:apply-templates select="node()"/>
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="template2" match="node1[.='']"/>

على الرغم من أن الكود الخاص بي يعمل ، إلا أنني لست سعيدًا بجماله من الكود .. هل هناك على أي حال للتخلص من خطوط زائدة (إن وجدت) .... وهل هناك أي بديل لاستخدام قوالب لإنجاز هذا (أي Template1 و قالب 2) ، هل من الممكن تقليل عدد القوالب؟

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

المحلول

I. XSLT 1.0 الحل:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:variable name="vReplacement">Default</xsl:variable>

       <xsl:variable name="vRep" select=
        "document('')/*/xsl:variable[@name='vReplacement']/text()"/>

     <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
     </xsl:template>

     <xsl:template match="node1[not(node())] | node2[../node1[not(node())]]">
      <xsl:copy>
          <xsl:copy-of select="../node2/text() | $vRep[not(current()/../node2/text())]"/>
      </xsl:copy>
     </xsl:template>
</xsl:stylesheet>

إنه أقصر وأبسط من الحلول الحالية - 7 خطوط أقل و ، الأهم من ذلك ، قالب واحد أقل من الحل المحدد حاليا.

والأهم من ذلك, ، هذا الحل التصريح تمامًا وعلى غرار الدفع-لا يوجد دعوة للقوالب المسماة والوحيدة <xsl:apply-templates> هو في قاعدة الهوية.

الثاني. XSLT 2.0 الحل

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
 </xsl:template>

 <xsl:template match="node1[not(node())] | node2[../node1[not(node())]]">
  <xsl:copy>
      <xsl:sequence select="(../node2/text(), 'Default')[1]"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

باستخدام قوة تسلسل XPath 2.0 هذا الحل أقصر تمامًا من حل XSLT 1.0.

شيء مشابه غير ممكن في XSLT 1.0 (مثل اختيار أول اتحاد العقدتين دون تحديد مسببات لجعل العقدتين حصريتين بشكل متبادل) ، لأن العقدة مع النص الافتراضي وعقد Node1/Node2 تنتمي إلى مستندات مختلفة ، وكما نعلم جيدًا ، فإن طلب العقدة بين العقد من المستندات المختلفة هو تطبيق محدد ولا يضمن/محدد.

هذا الحل التصريح تماما (لا إذا/ثم/آخر) ودفع الأسلوب تمامًا: الوحيد <xsl:apply-templates> هو في قاعدة الهوية.

نصائح أخرى

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="node1[.=''] | node2[.='']">
    <xsl:copy>
      <xsl:call-template name="GetOwnValue" />
    </xsl:copy>
  </xsl:template>

  <xsl:template name="GetOwnValue">
    <xsl:variable name="node2" select="following-sibling::node2[1]" />
    <xsl:choose>
      <xsl:when test="$node2 != ''">
        <xsl:value-of select="$node2" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>Default</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

لقد عدلت تومالاكإجابة وإنجاز الشرط ..
كما ذكرت في سؤالي ، فإن هذا الرمز يمرر Node2 على أنه فارغ (إذا كان فارغًا) إذا لم يكن Node1 Node1 خاليًا (وأيضًا إذا لم يكن هناك Node1) ..

أصبح هذا الرمز أخيرًا بديلاً عن الكود الذي نشرته في Q .. (لا أقول إنه مثالي بما فيه الكفاية .. لكنني سعيد لأنني أستطيع أن أحاول .. :-)
وهذا الرمز أكثر كفاءة من حوالي 10-20 ميللي ثانية .. :-)

من هنا تبدأ ..

  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="node1[.=''] | node2[.='']">
    <xsl:copy>
      <xsl:call-template name="GetOwnValue">
        <xsl:with-param name="node">
          <xsl:value-of select="name()"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:copy>
  </xsl:template>

  <xsl:template name="GetOwnValue">
    <xsl:param name="node"/>
    <xsl:variable name="node2" select="following-sibling::node2[1]|preceding-sibling::node2[1]" />
    <xsl:variable name="node1" select="following-sibling::node1[1]|preceding-sibling::node1[1]" />
     <xsl:choose>
      <xsl:when test="$node2 != ''">
          <xsl:value-of select="$node2" />
      </xsl:when>
       <xsl:when test="$node!='node1' and ($node1!='' or not(following-sibling::node1[1]|preceding-sibling::node1[1]))"/>
      <xsl:otherwise>
          <xsl:text>Default</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

باستخدام XSLT 2.0 سأفعل ذلك ، لكن من الأسهل قراءتك على أي حال.

<xsl:template match="node1[.='']">
    <xsl:copy>
        <xsl:value-of select="if (following-sibling::node2[.!='']) then following-sibling::node2[.!=''] else if (preceding-sibling::node2[.!='']) then preceding-sibling::node2[.!=''] else 'Default'"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="node2[.='']">
    <xsl:copy>
        <xsl:value-of select="if (following-sibling::node1[.!='']) then '' else if (preceding-sibling::node1[.!='']) then '' else 'Default'"/>
    </xsl:copy>
</xsl:template>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top