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:
- Iterate every item that contains a template tag
- For each one get the associated template of the templates document
- Copy everything inside the template into the object (*)
- 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.
Just for fun, this XSLT 1.0 stylesheet:
With this input:
Output: