我有两个XML,一个用于定义应用程序对象的模板。和另一个与实际的对象。基本上在每个对象中只改变了一些值,这就是为什么我想提供某种模板机制并应用XSL将它们转换为最终的。
这是一个示例对象:
<config>
<objects>
<object code="1000" name="object1">
<template name="decoration" buyCoins="60" />
</object>
</objects>
这是该对象的示例模板:
<config xmlns:template="object-template">
<templates>
<template name="decoration">
<connection type="make" />
<placeable width="1" length="1" moveable="true" collision="D" />
<buyable>
<requirement template:coins="buyCoins"/>
<reward xp="1" />
</buyable>
<sellable>
<reward coins="1"/>
</sellable></template></templates></config>
这是我目前的XSL:
<xsl:variable name="templates" select="document('../templates.xml')/config/templates//template" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//template">
<xsl:variable name="itemTemplate" select="."/>
<xsl:variable name="templateName" select="@name"/>
<xsl:variable name="selectedTemplate" select="$templates[@name = $templateName]/*" />
<xsl:for-each select="$selectedTemplate">
<!-- This part is only a test to get the values that I need -->
<xsl:for-each select=".//@*[namespace-uri() = 'object-template']">
<xsl:variable name="attributeName" select="name()"/>
<xsl:variable name="attributeValue" select="."/>
<xsl:variable name="finalValue" select="$itemTemplate/@*[local-name() = $attributeValue]"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template match="comment()"/>
我只需要执行以下操作:
说明:
(*)申请
<template name="test"><node></template>
到
<object><template name="test"></object>
成为
<object><node></object>
(**)在上面的原始示例中,项目模板标记的buyCoins值应该在将文件“buyCoins”发送到输出之前替换模板的值。轻松查找并避免注册。进出口。我正在使用命名空间。因此,我在XSL中所做的是使用正确的命名空间搜索模板内的所有属性并搜索值。 应在硬币属性中放置值“60”而不是“buyCoins”。
我的问题是我不明白如何复制所有内容(我相信这被称为身份副本),但取代了我需要的价值。
任何帮助将不胜感激,谢谢!
更新
目前的输出是:
<config xmlns:template="item-template">
<objects>
<object code="1000" name="object1" type="decorations">
</object>
</object>
如果我把:
<xsl:copy-of select="."/>
下面:
<xsl:for-each select="$selectedTemplate">
然后我得到:
<objects>
<object code="1000" name="object1">
<connection type="make" /><placeable width="1" length="1" moveable="true" collision="D" />
<buyable>
<requirement template:coins="buyCoins"/>
<reward xp="1" />
</buyable>
<sellable>
<reward coins="1"/>
</sellable>
</object></objects>
这是我需要的第一部分,在每个输出项上放置与之关联的模板的内容。我现在在更换值时遇到问题。
XSL中的这些树线表示我需要的数据:
<xsl:variable name="attributeName" select="name()"/>
<xsl:variable name="attributeValue" select="."/>
<xsl:variable name="finalValue" select="$itemTemplate/@*[local-name() = $attributeValue]"/>
对于此示例中的唯一项目,这是每个变量的内容: attributeName将包含“template:coins” attributeValue将包含“buyCoins” finalValue将包含“60”
我需要在该attributeName的标记中放入finalValue而不是attributeValue。
那时我被卡住了:(
谢谢!
更新2:
为了避免误解,这里是我需要的精确输出:
<objects>
<object code="1000" name="object1">
<connection type="make" /><placeable width="1" length="1" moveable="true" collision="D" />
<buyable>
<requirement coins="60"/>
<reward xp="1" />
</buyable>
<sellable>
<reward coins="1"/>
</sellable>
</object></objects>
而不是属性硬币中的“buyCoins”,我需要它为“60”(输入对象文件中的值)。 另外,最好的输出也应该删除属性的命名空间模板,因为它只是XSL的一个标志,用于知道要修改的属性。
答案 0 :(得分:0)
只是为了好玩,这个XSLT 1.0样式表:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:template="object-template"
exclude-result-prefixes="template">
<xsl:key name="kTemplateByName" match="templates/template" use="@name"/>
<xsl:template match="*">
<xsl:param name="pContext"/>
<xsl:element name="{name()}">
<xsl:copy-of select="namespace::*[.!='object-template']"/>
<xsl:apply-templates select="node()|@*">
<xsl:with-param name="pContext" select="$pContext"/>
</xsl:apply-templates>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="templates"/>
<xsl:template match="config">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="template">
<xsl:apply-templates select="key('kTemplateByName',@name)/node()">
<xsl:with-param name="pContext" select="."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@template:*">
<xsl:param name="pContext"/>
<xsl:attribute name="{local-name()}">
<xsl:value-of select="$pContext//@*[name()=current()]"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
使用此输入:
<config xmlns:template="object-template">
<objects>
<object code="1000" name="object1">
<template name="decoration" buyCoins="60" />
</object>
</objects>
<templates>
<template name="decoration">
<connection type="make" />
<placeable width="1" length="1" moveable="true" collision="D" />
<buyable>
<requirement template:coins="buyCoins"/>
<reward xp="1" />
</buyable>
<sellable>
<reward coins="1"/>
</sellable>
</template>
</templates>
</config>
输出:
<objects>
<object code="1000" name="object1">
<connection type="make"></connection>
<placeable width="1" length="1" moveable="true" collision="D"></placeable>
<buyable>
<requirement coins="60"></requirement>
<reward xp="1"></reward>
</buyable>
<sellable>
<reward coins="1"></reward>
</sellable>
</object>
</objects>
答案 1 :(得分:0)
这是传统的XSLT解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:template="object-template" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:param name="pParams"/>
<xsl:copy>
<xsl:apply-templates select="node()|@*">
<xsl:with-param name="pParams"
select="$pParams"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="template">
<xsl:apply-templates select="
/*/templates/template[@name = current()/@name]/node()">
<xsl:with-param name="pParams" select="@*"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@template:*">
<xsl:param name="pParams"/>
<xsl:attribute name="{local-name()}">
<xsl:value-of select="$pParams[name()=current()]"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="templates"/>
</xsl:stylesheet>
将此转换应用于followinf XML文档:
<config xmlns:template="object-template">
<objects>
<object code="1000" name="object1">
<template name="decoration"
buyCoins="60" />
</object>
</objects>
<templates>
<template name="decoration">
<connection type="make" />
<placeable width="1" length="1"
moveable="true" collision="D" />
<buyable>
<requirement template:coins="buyCoins"/>
<reward xp="1" />
</buyable>
<sellable>
<reward coins="1"/>
</sellable>
</template>
</templates>
</config>
产生了想要的正确结果:
<config xmlns:template="object-template">
<objects>
<object code="1000" name="object1">
<connection type="make"/>
<placeable width="1" length="1" moveable="true" collision="D"/>
<buyable>
<requirement coins="60"/>
<reward xp="1"/>
</buyable>
<sellable>
<reward coins="1"/>
</sellable>
</object>
</objects>
</config>
请注意:
使用身份规则(模板)“按原样”复制所有节点。身份规则的使用和覆盖是最基本的XSLT设计模式。
我们正在使用的身份规则被修改为接受并传递名为pParams
的单个参数。此参数是引用特定模板的object/template
元素的所有属性的集合。
任何object/template
元素都与xsl:template 匹配,从而覆盖了身份规则。它只会将<xsl:apply-templates>
发布到相应的节点(由@name
- templates\template
元素匹配。
匹配的templates\template
元素下方的所有节点都按照由身份规则复制,但"object-template"
命名空间中的任何属性除外。< / p>
模板匹配"object-template"
命名空间中具有名称的任何属性,从而覆盖标识规则。此xsl:template使用pParams
参数在其中查找与当前匹配的属性值具有相同名称的属性。这样找到的“parameter-attribute”的值被用作新创建的属性的值,该属性与当前匹配的属性具有相同的local-name()
,但是没有名称空间。
与任何templates
元素匹配的空模板会阻止复制此子树的身份规则(第二次)。