كيفية الحصول على XML OUPUT المطلوب من XMLS باستخدام XSLT

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

  •  28-09-2019
  •  | 
  •  

سؤال

أنا أستخدم XSLT و XML.

أول شيء سأعمل على اثنين من XML.

أول XML:

<?xml version="1.0"?>
<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ID="tcm:232-83752-2" Managed="10682">  
  <tcm:Item ID="tcm:232-564598" Title="010 News Mapping"/>
  <tcm:Item ID="tcm:232-564599" Title="020 CUGOs"/>
  <tcm:Item ID="tcm:232-614307" Title="030 Reserved Urls"/>
</tcm:ListItems>

ال الثاني XML سنحصل عليه باستخدام المعرف أعلاه ، أي TCM: 232-564598 وما إلى ذلك ، فيما يلي أحد XML لـ ID TCM: 232-564598 وسيكون معرفات أخرى نفس النوع من XML.

<tcm:Component ID="tcm:229-564598" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink">
  <tcm:Data>
    <tcm:Content>
      <MappingCollection xmlns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F">
        <VanityUrl>
          <old>mbp</old>
          <new>/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f</new>
          <dateAdded>2010-05-03T14:45:00</dateAdded>
          <comments> News mapping </comments>
        </VanityUrl>
        <VanityUrl>
          <old>about/news</old>
          <new>about/news/news.aspx</new>
          <dateAdded>2010-05-03T14:45:00</dateAdded>
          <comments> News mapping </comments>
        </VanityUrl>
      </MappingCollection>
    </tcm:Content>
  </tcm:Data>
</tcm:Component>

أحاول الحصول على أدناه تنسيق XML باستخدام أعلاه كلا XMLs.

<?xml version="1.0" encoding="UTF-8"?>
<mappings>
    <!-- News mapping -->
    <mapping old="mbp" new="/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f"/>
    <mapping old="about/news" new="about/news/news.aspx"/>
    <!-- CUGO's-->
    <mapping old="/nhs" new="/cugo.aspx?promoCode=UKNHS01&amp;pub=/uk/english"/>
    <mapping old="/hk/ukstudentfare" new="/cugo.aspx?promoCode=HKSTU10&amp;pub=/hk/Chinese"/>
</mappings> 

وهنا XSLT الخاص بي حيث أحاول إنشاء التنسيق أعلاه XML ولكنه لا يعمل بالنسبة لي. يرجى ملاحظة First XML هو XML الأساسي الذي سيتم تحويله باستخدام XSLT أدناه

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:em="http://www.espire.com/tridion/schemas" xmlns:tcmse="http://www.tridion.com/ContentManager/5.1/TcmScriptAssistant" exclude-result-prefixes="em xlink tcmse tcm">
  <xsl:output method="xml" version="1.0" encoding="UTF-16" indent="yes"/>
  <!-- root match-->
  <xsl:template match="tcm:ListItems">
    <mappings>
      <xsl:apply-templates select="tcm:Item"/>
    </mappings>
  </xsl:template>
  <xsl:template match="tcm:Item">
      <xsl:variable name="doc" select="document(@ID)"/>
    <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
      <xsl:comment>
        <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
      </xsl:comment>
    </xsl:if>  
    <xsl:for-each select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl">
        <xsl:element name="mapping">
          <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:old">
            <xsl:attribute name="old">
              <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:old"/>
            </xsl:attribute>
          </xsl:if>
          <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:new">
            <xsl:attribute name="new">
              <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:new"/>
            </xsl:attribute>
          </xsl:if>
          <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:dateAdded">
            <xsl:attribute name="dateAdded">
              <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:dateAdded"/>
            </xsl:attribute>
          </xsl:if>
        </xsl:element>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

في أعلاه XSLT ، أتمكن من الحصول على حلقة البيانات أيضًا بشكل صحيح ولكن البيانات التي كانت قادمة هي نفسها ، أعني أن الحلقة تعمل بشكل صحيح ، لكن قيمة العقدة هي نفسها

الرجاء الاقتراح!

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

المحلول

ورقة الأنماط هذه:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"
 xmlns:tcm="http://www.tridion.com/ContentManager/5.0"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="ns tcm msxsl">
    <xsl:strip-space elements="*"/>
    <xsl:key name="kVanityByComment" match="ns:VanityUrl" use="ns:comments"/>
    <xsl:template match="/">
        <xsl:variable name="vSourcesRTF">
            <xsl:copy-of select="document(tcm:ListItems/tcm:Item/@ID)"/>
        </xsl:variable>
        <mappings>
            <xsl:apply-templates select="msxsl:node-set($vSourcesRTF)/node()"/>
        </mappings>
    </xsl:template>
    <xsl:template match="ns:VanityUrl"/>
    <xsl:template match="ns:VanityUrl[generate-id()=
                                      generate-id(key('kVanityByComment',
                                                      ns:comments)[1])]">
        <xsl:comment>
            <xsl:value-of select="ns:comments"/>
        </xsl:comment>
        <xsl:apply-templates select="key('kVanityByComment',
                                         ns:comments)"
                             mode="output"/>
    </xsl:template>
    <xsl:template match="ns:VanityUrl" mode="output">
        <mapping>
            <xsl:apply-templates/>
        </mapping>
    </xsl:template>
    <xsl:template match="ns:VanityUrl/ns:comments" priority="1"/>
    <xsl:template match="ns:VanityUrl/*">
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

مع هذا المدخلات:

<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ID="tcm:232-83752-2" Managed="10682">
  <tcm:Item ID="229-564598" Title="010 News Mapping"/>
  <tcm:Item ID="229-564598" Title="020 CUGOs"/>
  <tcm:Item ID="229-564598" Title="030 Reserved Urls"/>
</tcm:ListItems>

وهذا المصدر الخارجي مع 229-564598 أوري:

<tcm:Component ID="tcm:229-564598" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink">
  <tcm:Data>
    <tcm:Content>
      <MappingCollection xmlns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F">
        <VanityUrl>
          <old>mbp</old>
          <new>/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f</new>
          <dateAdded>2010-05-03T14:45:00</dateAdded>
          <comments> News mapping </comments>
        </VanityUrl>
        <VanityUrl>
          <old>about/news</old>
          <new>about/news/news.aspx</new>
          <dateAdded>2010-05-03T14:45:00</dateAdded>
          <comments> News mapping </comments>
        </VanityUrl>
      </MappingCollection>
    </tcm:Content>
  </tcm:Data>
</tcm:Component>

انتاج:

<mappings>
    <!-- News mapping -->
    <mapping old="mbp" 
             new="/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f"
             dateAdded="2010-05-03T14:45:00"></mapping>
    <mapping old="about/news"
             new="about/news/news.aspx"
             dateAdded="2010-05-03T14:45:00"></mapping>
</mappings>

تعديل: مصادر إدخال متعددة.

نصائح أخرى

نعم ، التغيير الذي أجريته أمر بالغ الأهمية. :-)

ما تفعله حلقة EACH هو تحديد كل منها <em:VanityUrl> العنصر الذي يطابق تعبير XPath الخاص بك ، اجعل هذا العنصر عقدة السياق لما يوجد داخل EACH (يسمى قالب على الرغم من أنها ليست <xsl:template>) ، ثم قم بتثبيت هذا القالب الداخلي مع عقدة السياق الجديدة.

عندما كنت تستمر في استخدام "$ doc/..." داخل الحلقة التي تم إجراؤها ، كنت تطرد عقدة السياق ، لذلك لم يكن للتأثير أي تأثير (باستثناء تكرار الأوقات).

لك <xsl:if test="$doc/..."> كانت البيانات تقيم ما إذا كان هناك أي عقدة من هذا القبيل في الوثيقة بأكملها بدلا من تحت عنصر السياق <em:VanityUrl>.

ال <xsl:value-of> يولي العبارة الانتباه إلى العقدة الأولى فقط في العقد المحددة ، لذلك كنت دائمًا تحصل على القيمة من أول <em:VanityUrl>, ، بغض النظر عن عقدة السياق.

عندما بدأت في اختيار واختبار عقدة السياق:

    <xsl:if test="em:old">

أصبح كل شيء أفضل. :-)

لقد طلبت مدخلات قيمة. لأسباب أسلوبية ، قد ترغب في استبدالك <xsl:if> اختبارات مع <xsl:apply-templates>. (لشيء واحد ، ستجعل dimitre novatchev سعيد. :-) إذن

<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
  <xsl:comment>
    <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
  </xsl:comment>
</xsl:if>

يصبح

<xsl:apply-templates select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments" />

ثم تحتاج إلى قالب منفصل لهؤلاء:

<xsl:template match="em:comments">
  <xsl:comment>
    <xsl:value-of select="."/>
  </xsl:comment>
</xsl:template>

هناك العديد من المزايا للقيام بذلك. الأكبر هو أنه ليس عليك تكرار تعبير XPath الطويل ، والذي كان معرضًا للخطأ إذا كان التعبير بحاجة إلى تعديله. إذا لم يكن هناك EM: عناصر التعليقات ، فلن تفعل Tamptions أي شيء ، لذلك لن تنبعث منها تعليق.

كما أنه يعدل ورقة الأنماط الخاصة بك ، بحيث يمكنك تعديل كيفية تقديم EM: التعليقات ، بشكل منفصل عن أي مكان قد تحدث. قد لا يهم ذلك كثيرًا في مستندات XML البسيطة التي تحدث فيها EM: التعليقات في مكان واحد فقط ، ولكن الأسلوب الذي يستفيد من قوة XSLT بشكل أفضل. لاحظ أيضًا أن هذا الإصدار المعدل سيؤدي إلى إخراج تعليقات متعددة إذا كان هناك العديد من التعليقات: لن يكون الإصدار الخاص بك. مرة أخرى ، ربما لا يكون لديك مضاعفات في المدخلات ، لذلك قد لا يهم.

وبالمثل بالنسبة لسمات الإخراج:

    <xsl:if test="em:old">
      <xsl:attribute name="old">
        <xsl:value-of select="em:old"/>
      </xsl:attribute>
    </xsl:if>

يمكن أن تصبح

    <xsl:apply-templates select="em:old[1]" />

مع قالب منفصل

<xsl:template match="em:old">
   <xsl:attribute name="old">
     <xsl:value-of select="."/>
   </xsl:attribute>
</xsl:template>

لاحظ ال [1], الذي يتجنب محاولة الإخراج المتعدد old="..." سمات لنفس العنصر إذا كان الإدخال em: vanityurl يحتوي على em: عناصر قديمة. سيؤدي ذلك إلى رفع ورقة الأنماط الخاصة بك. ولكن ربما أنت يريد لرفع خطأ في هذه الحالة. إذا كان الأمر كذلك ، فربما تقوم بالفعل بالتحقق من صحة إدخال XML.

في الواقع ، يمكنك تعميم الأملس والقالب هنا للتقدم على جميع السمات الثلاث:

    <xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]" />

مرة أخرى ، إذا لم يكن أي من هذه العناصر موجودة ، فلن يتم القيام بأي شيء بالنسبة لهم (لن يتم إنتاج أي سمة فارغة). القالب:

<xsl:template match="em:old | em:new | em:dateAdded">
   <xsl:attribute name="{local-name()}">
     <xsl:value-of select="."/>
   </xsl:attribute>
</xsl:template>

local-name() يعطينا اسم العنصر ، دون بادئة مساحة الاسم.

تحديث:

هناك طريقة أخرى للتعامل مع ذلك لاستخدام الوضع:

    <xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]"
      mode="make-attribute" />

<xsl:template match="em:*" mode="make-attribute">
   <xsl:attribute name="{local-name()}">
     <xsl:value-of select="."/>
   </xsl:attribute>
</xsl:template>

بعد ذلك ، يمكن استخدام قالب Make-Attribute من أي مكان ، ولا يجب تحديث نمط المطابقة لمطابقة كل عنصر ممكن قد ترغب في صنعه من السمة.

الشيء الآخر الوحيد الذي أود أن أقوله هو أن استخدام مساحات الأسماء أعلاه أمر مربك ... لا ينبغي أن يعمل كما هو. على سبيل المثال ، تستخدم ورقة الأنماط الخاصة بك مساحة الاسم هذه لعناصر مثل Vanityurl:

 "http://www.espire.com/tridion/schemas"

لكن مستند الإدخال الثاني يستخدم مساحة الاسم هذه URI لتلك العناصر:

 "uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"

لا يهم أن بادئة مساحة الاسم مختلفة ("EM:" مقابل الافتراضي) ، ولكن يجب أن تتطابق مساحة الاسم URIS. أعتقد أن مساحة اسم Vanityurl يجب أن يكون URI قد تغير ، وإلا فلن تعمل ورقة الأنماط الخاصة بك ...

هول!

يمكنك تجربة هذا أيضا !!

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:em="http://www.espire.com/tridion/schemas" xmlns:tcmse="http://www.tridion.com/ContentManager/5.1/TcmScriptAssistant" exclude-result-prefixes="em xlink tcmse tcm">
  <xsl:output method="xml" version="1.0" encoding="UTF-16" indent="yes"/>     
  <!-- root match-->
  <xsl:template match="tcm:ListItems">
    <mappings>
      <xsl:apply-templates select="tcm:Item"/>
    </mappings>
  </xsl:template>
  <xsl:template match="tcm:Item">
    <xsl:variable name="doc" select="document(@ID)"/>
    <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
      <xsl:comment>
        <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
      </xsl:comment>
    </xsl:if>
    <xsl:for-each select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl">
      <xsl:element name="mapping">
        <xsl:if test="em:old">
          <xsl:attribute name="old">
            <xsl:value-of select="em:old"/>
          </xsl:attribute>
        </xsl:if>
        <xsl:if test="em:new">
          <xsl:attribute name="new">
            <xsl:value-of select="em:new"/>
          </xsl:attribute>
        </xsl:if>
        <xsl:if test="em:dateAdded">
          <xsl:attribute name="dateAdded">
            <xsl:value-of select="em:dateAdded"/>
          </xsl:attribute>
        </xsl:if>
      </xsl:element>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top