如何使用XSLT从两个XML获得所需的XML uPUT
题
我正在使用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等获得它,以下是ID TCM的XML之一:232-564598,其他IDS将具有相同类型的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&pub=/english&section=IBE&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&pub=/english&section=IBE&j=f"/>
<mapping old="about/news" new="about/news/news.aspx"/>
<!-- CUGO's-->
<mapping old="/nhs" new="/cugo.aspx?promoCode=UKNHS01&pub=/uk/english"/>
<mapping old="/hk/ukstudentfare" new="/cugo.aspx?promoCode=HKSTU10&pub=/hk/Chinese"/>
</mappings>
这是我试图生成上述格式XML的XSLT,但对我不起作用。请注意,首先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&pub=/english&section=IBE&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&pub=/english&section=IBE&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>
编辑: :多个输入源。
其他提示
是的,您所做的更改确实至关重要。 :-)
EAPH循环的作用是选择每个 <em:VanityUrl>
匹配您的xpath表达式的元素,使该元素成为for-each内部内容的上下文节点(称为 模板 即使不是 <xsl:template>
),然后使用新的上下文节点实例化该模板。
当您继续在for-EAPL循环内使用“ $ doc/...”时,您将扔掉上下文节点,因此for-EATH没有效果(除了重复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文档中,这可能并不重要,其中Em:注释仅在一个地方出现,但是风格最好地利用了XSLT的力量。另请注意,如果有多个EM:注释,则此修改版将输出多个注释,而您的版本不会。同样,您可能没有输入中的倍数,因此可能无关紧要。
同样,对于输出属性:
<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模板,并且不必更新匹配模式即可匹配您可能想从中制作属性的所有可能元素。
我唯一要说的是,上面的名称空间的使用令人困惑……它不应像IS一样起作用。例如,您的样式表使用此命名空间URI作为VanityUrl等元素:
"http://www.espire.com/tridion/schemas"
但是第二个输入文档对这些元素使用此命名空间URI:
"uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"
名称空间前缀是不同的(“ em:” vs.默认值)都没关系,但是命名空间URI必须匹配。我猜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>