0

我正在使用 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>

我们将使用上面的 ID 获取第二个 XML,即 tcm:232-564598 等,下面是 ID tcm:232-564598 的 xml 之一,其他 ID 将具有相同类型的 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 中,我能够得到数据循环也正确,但即将到来的数据是相同的,我的意思是循环执行正确,但节点值是相同的

请建议!

4

3 回答 3

2

这个样式表:

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

编辑:多个输入源。

于 2010-11-03T13:15:15.603 回答
1

是的,你所做的改变确实很关键。:-)

for-each 循环所做的是选择<em:VanityUrl>与您的 XPath 表达式匹配的每个元素,使该元素成为 for-each 内部内容的上下文节点(即使它不是一个,也称为模板<xsl:template>),然后使用新上下文实例化该内部模板节点。

当您在 for-each 循环中继续使用“$doc/...”时,您正在丢弃上下文节点,因此 for-each 没有任何效果(除了重复 n 次)。

您的陈述正在评估整个文档中<xsl:if test="$doc/...">是否存在任何此类节点,而不是在 context 元素下。<em:VanityUrl>

<xsl:value-of>语句只关注所选节点集中的第一个节点,因此无论上下文节点如何,您总是从first获取值。 <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:comment 元素,apply-templates 不会做任何事情,因此不会发出评论。

它还模块化了您的样式表,以便您可以修改 em:comments 的呈现方式,与它们可能出现的位置分开。在 em:comments 只出现在一个地方的简单 XML 文档中,这可能无关紧要,但它是最能利用 XSLT 功能的样式。另请注意,如果有多个 em:comments,此修改后的版本将输出多个注释,而您的版本不会。同样,您可能在输入中没有倍数,因此可能无关紧要。

同样对于输出属性:

    <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],如果输入 em:VanityUrl 有多个 em:old 元素,它会避免尝试old="..."为同一元素输出多个属性。这将导致您的样式表引发错误。但也许你在这种情况下引发错误。如果是这样,您可能已经在验证您的输入 XML。

实际上,您可以在这里泛化 apply-templates 和 template 以应用于所有三个属性:

    <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 模板,并且不必更新匹配模式以匹配您可能希望从中创建属性的每个可能元素。

我要说的唯一另一件事是上面的名称空间的使用令人困惑……它不应该按原样工作。例如,您的样式表将这个命名空间 URI 用于 VanityURL 等元素:

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

但第二个输入文档对这些元素使用此命名空间 URI:

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

命名空间前缀不同(“em:”与默认值)并不重要,但命名空间 URI 必须匹配。我猜 VanityURL 的命名空间 URI 一定已经改变,否则你的样式表将无法工作......

于 2010-11-03T11:58:50.053 回答
1

你也可以试试这个!!

<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>
于 2013-01-16T17:35:07.037 回答