XSLT:如何使用源和第二个文件创建输出?

时间:2011-01-19 19:33:15

标签: xml templates xslt transformation xslt-2.0

我有两个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()"/>

我只需要执行以下操作:

  1. 迭代包含模板标记的每个项目
  2. 为每个人获取模板文档的相关模板
  3. 将模板内的所有内容复制到对象(*)
  4. 将项目内的属性值(现在粘贴模板)替换为原始模板中的实际值(**)
  5. 说明:

    (*)申请

     <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的一个标志,用于知道要修改的属性。

2 个答案:

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

请注意

  1. 使用身份规则(模板)“按原样”复制所有节点。身份规则的使用和覆盖是最基本的XSLT设计模式。

  2. 我们正在使用的身份规则被修改为接受并传递名为pParams的单个参数。此参数是引用特定模板的object/template元素的所有属性的集合。

  3. 任何object/template元素都与xsl:template 匹配,从而覆盖了身份规则。它只会将<xsl:apply-templates>发布到相应的节点(由@name - templates\template元素匹配。

  4. 匹配的templates\template元素下方的所有节点都按照由身份规则复制,但"object-template"命名空间中的任何属性除外。< / p>

  5. 模板匹配"object-template"命名空间中具有名称的任何属性,从而覆盖标识规则。此xsl:template使用pParams参数在其中查找与当前匹配的属性值具有相同名称的属性。这样找到的“parameter-attribute”的值被用作新创建的属性的值,该属性与当前匹配的属性具有相同的local-name(),但是没有名称空间。

  6. 与任何templates元素匹配的空模板会阻止复制此子树的身份规则(第二次)。