Как получить желаемую XML Ouput из двух XML с использованием 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 Мы получим его, используя вышеуказанные ID IE 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, используя выше как XML.

<?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, но это не работает для меня. Обратите внимание, первым 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 Uri:

<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>

РЕДАКТИРОВАТЬ: Несколько входных источников.

Другие советы

Да, изменение, которое вы сделали, действительно критичны. :-)

Что за-каждая петля определяет каждый <em:VanityUrl> Элемент, соответствующий вашему выражению XPath, сделать этот элемент контекстным узлом для того, что находится внутри для каждого (называемого шаблон Хотя это не <xsl:template>), а затем создать этот внутренний шаблон с новым узлом контекста.

Когда вы продолжали использовать «$ DOC / ...» внутри цикла для каждого цикла, вы бросали узел контекста, поэтому у каждого не было никакого эффекта (за исключением повторения N раз).

Ваш <xsl:if test="$doc/..."> заявления оценивали, был ли любой такой узел во всем документе вместо под контексте <em:VanityUrl>.

То <xsl:value-of> Заявление уделяет внимание только на первом узле в выбранном NoDeset, поэтому вы всегда получали значение из первый <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: комментарий элементы, применяемые шаблоны ничего не сделают, поэтому не выделяет комментарий.

Он также модулярует вашу таблицу стилей, чтобы вы могли изменить, как em: Комментарии отображаются отдельно от того, где они могут произойти. Это может не иметь значения слишком большого значения в простых XML-документов, где их: комментарии происходят только в одном месте, но это стиль, который занимает наилучшее преимущество власти 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>

Затем ваш шаблон Attribute можно использовать из любого места, и шаблон совпадения не должен быть обновлен, чтобы соответствовать каждому возможному элементу, который вы можете сделать атрибут.

Единственная вещь, которую я бы сказал, это то, что использование пространств имен выше сбивает с толку ... это не должно работать как есть. Например, ваша таблица стилей использует это URI пространства имен для элементов, таких как Vanityurl:

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

Но второй входной документ использует это URI пространства имен для этих элементов:

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

Неважно, что префикс пространства имен отличается («EM:» против по умолчанию), но URI пространства имен должен соответствовать. Я думаю, что пространство имен Vanityurl, должно быть, не должно измениться, или иначе ваша таблица стилей не будет работать ...

HTH!

Вы можете попробовать это тоже!

<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