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

发布于 2024-10-12 20:21:51 字数 4593 浏览 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. 替换项目内的属性值(现在为粘贴的模板)与原始模板中的实际值 (**)

说明:

(*) 应用

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

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

变为

<object><node></object>

(**) 在上面的原始示例中,商品模板标签的 buyCoins 值应替换在将其发送到输出之前发送文本“buyCoins”。为了方便查找并避免注册。实验值。我正在使用命名空间。因此,我在 XSL 中所做的就是使用正确的命名空间搜索模板内的所有属性并搜索值。 应在 coin 属性中输入值“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”,而不是“buyCoins” (输入对象文件中的值)。 此外,最好的输出还应该删除属性的名称空间模板,因为它只是 XSL 知道要修改哪些属性的标志。

I have two XMLs, one for defining the templates for the objects of my app. and another with the actual objects. Basically in each object only a few values are changed, that's why I wanted to provide some kind of template mechanism and apply XSL to transform them into the final one.

This is a sample object:

<config>
<objects>
    <object code="1000" name="object1">
        <template name="decoration" buyCoins="60" />
    </object>
</objects>

And this is a sample template for that object:

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

This is my current 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()"/>

I just need to do the following:

  1. Iterate every item that contains a template tag
  2. For each one get the associated template of the templates document
  3. Copy everything inside the template into the object (*)
  4. Replace the values of the attributes inside the item (now with the template pasted) with the real value in the original template (**)

Explanation:

(*) Apply

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

to

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

becomes

<object><node></object>

(**) In the original sample above, the value of buyCoins of the item's template tag should replace the template's value of the text "buyCoins" before sending it into the output. For easy lookup and to avoid reg. exp. I am using namespaces. So what I do in the XSL is to search for all the attributes inside the template with the right namespace and search for the values.
The value "60" should be put instead of "buyCoins" inside the coins attribute.

My problem is that I don't understand how to copy everything (I believe that is called an identity copy) but replace the value that I need.

Any help will be appreciated, thanks!!!

UPDATE:

The current output is:

<config xmlns:template="item-template">
<objects>   
    <object code="1000" name="object1" type="decorations">
    </object>
</object>

If I put:

<xsl:copy-of select="."/>

Below:

<xsl:for-each select="$selectedTemplate">

Then I get:

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

That is the first part of what I need, to put on each output item the content of the template associated to it. I am having problems replacing the values now.

These tree lines in the XSL represents the data that I need:

        <xsl:variable name="attributeName" select="name()"/>
        <xsl:variable name="attributeValue" select="."/>
        <xsl:variable name="finalValue" select="$itemTemplate/@*[local-name() = $attributeValue]"/>

For the only item in this example this is the content of each variable:
attributeName will contain "template:coins"
attributeValue will contain "buyCoins"
finalValue will contain "60"

I need to put finalValue instead of attributeValue in the tag of that attributeName.

At that point I am stuck :(

Thanks!

Update 2:

To avoid misunderstandings, here is the EXACT output that I need:

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

Instead of "buyCoins" in the attribute coins I need it to be "60" (The value in the input objects file).
Also the best possible output should remove the namespace templates of the attributes too, because its only a flag for the XSL to know which attributes to modify.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

少女净妖师 2024-10-19 20:21:51

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

Just for fun, this XSLT 1.0 stylesheet:

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

With this input:

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

Output:

<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>
辞别 2024-10-19 20:21:51

这是一个传统的 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 匹配,从而覆盖身份规则。它只是向相应的节点发出 (通过 @name - templates\template 元素匹配。< /p>

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

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

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

Here is a traditional XSLT solution:

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

when this transformation is applied on the followinf XML document:

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

the wanted, correct result is produced:

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

Do note:

  1. The identity rule (template) is used to copy all nodes "as-is". The using and overriding of the identity rule is the most fundamental XSLT design pattern.

  2. The identity rule we are using is modified to accept and pass through a single parameter, named pParams. This parameter is the set of all attributes of the object/template element that references a particular template.

  3. Any object/template element is matched by an xsl:template that thus overrides the identity rule. It just issues <xsl:apply-templates> to the nodes of the corresponding (matching by @name - templates\template element.

  4. All nodes below the matched templates\template element are copied as is by the identity rule with the exception of any attribute that is in the "object-template" namespace.

  5. A template matches any atribute with name in the "object-template" namespace and thus overrides the identity rule. This xsl:template uses the pParams parameter to find in it an attribute that has the same name as the value of the currently matched attribute. The value of the "parameter-attribute" thus found is used as the value of a newly-created attribute that has the same local-name() as the currently matched attribute, but is in no namespace.

  6. An empty template matching any templates element prevents the identity rule of copying this subtree (for a second time).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文