【问题标题】:XSLT: How can I create an output using the source and this second file?XSLT:如何使用源文件和第二个文件创建输出?
【发布时间】:2011-01-19 19:33:15
【问题描述】:

我有两个 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. 将项目内的属性值(现在已粘贴模板)替换为原始模板中的实际值 (**)

解释:

(*) 申请

 <template name="test"><node></template> 

<object><template name="test"></object> 

变成

<object><node></object>

(**) 在上面的原始示例中,项目模板标签的 buyCoins 值应在将文本“buyCoins”发送到输出之前替换模板的值。为了便于查找并避免注册。 exp。我正在使用命名空间。所以我在 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 将包含“模板:硬币” attributeValue 将包含“buyCoins” finalValue 将包含“60”

我需要将 finalValue 而不是attributeValue 放在那个attributeName 的标签中。

那时我被卡住了:(

谢谢!

更新 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 知道要修改哪些属性的标志。

【问题讨论】:

  • 你错过了一些非常重要的东西:转换的确切输出。请。
  • 请提供所需的输出,然后我会给出必要的解决方案。
  • 感谢您的关注!我更新了问题。
  • 嗯...你提供你得到的输出。但我需要你想要的输出——请你提供那个输出吗?
  • 对不起,我的错误。我用该信息再次更新。

标签: xml templates xslt transformation xslt-2.0


【解决方案1】:

只是为了好玩,这个 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>

【讨论】:

  • 完美!我尝试使用带有新模板的 +100 个对象并使用该命名空间在属性中设置任何类型的值。似乎我遗漏了一些关键点(今天刚开始使用 XSL,不知道如何应用带有参数和键的模板)非常感谢!这只是为了好玩,但你让我开心:)。真的很感激!!!
  • @user581945:不客气!请注意,我在前两个规则中拆分了身份规则,因为您要求在范围命名空间中进行条带化。
【解决方案2】:

这是一个传统的 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>

当此转换应用于以下 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 匹配,从而覆盖标识规则。它只是向对应的节点发出&lt;xsl:apply-templates&gt;(匹配@name - templates\template 元素。

  4. 匹配的templates\template 元素下的所有节点都按原样复制,但"object-template" 命名空间中的任何属性除外。

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

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

【讨论】:

  • 非常感谢您的解释!我能够用第一个答案解决问题,但现在我对 XSL 概念有了更好的理解。感谢您花时间给我这个完整的答案。
  • @user581945:很高兴我的回答很有用。您是否知道在接受/支持答案时表达了感激之情?
猜你喜欢
  • 1970-01-01
  • 2010-11-10
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 2011-01-25
  • 2014-04-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多