Reputation: 1
I hate writing XSLT, mainly because I’m just no good at it. I have an XML data file where everything is an attribute instead of a direct value inside a meaningful node.
I’d like to run an XSLT Transform that could turn this:
<token-value-entry token-name="RECIPIENT_CITY">
<token-value><value>ROSEBURG</value></token-value>
</token-value-entry>
<token-value-entry token-name="RECIPIENT_STATE">
<token-value><value>OR</value></token-value>
</token-value-entry>
Into this:
<RECIPIENT_CITY>ROSEBURG</<RECIPIENT_CITY>
<RECIPIENT_STATE>OR</RECIPIENT_STATE>
Ok, another edit. When to stackoverflow become some pedantic?
Specific Question: is there a way to use the value of an attribute as the name of a new element?
I have this XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@token-name">
<xsl:element name="{name()}"><xsl:value-of select="."/></xsl:element>
</xsl:template>
</xsl:stylesheet>
Which produces this output:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<token-value-entry>
<token-name>RECIPIENT_CITY</token-name>
<token-value>
<value>ROSEBURG</value>
</token-value>
</token-value-entry>
<token-value-entry>
<token-name>RECIPIENT_STATE</token-name>
<token-value>
<value>OR</value>
</token-value>
</token-value-entry>
</root>
The question I would like answered, beyond "keep googling", is, what do I use instead of the {name()} variable, to output the value "RECIPIENT_CITY" as the name of the node?
For now, if I get could to this output, I'd likely be able to figure out the rest:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<token-value-entry>
<RECIPIENT_CITY />
<token-value>
<value>ROSEBURG</value>
</token-value>
</token-value-entry>
<token-value-entry>
<RECIPIENT_STATE />
<token-value>
<value>OR</value>
</token-value>
</token-value-entry>
</root>
Asked another way, how can I store the value of an attribute in a variable which I can use elsewhere to create an element?
Upvotes: 0
Views: 99
Reputation: 1
Lot of assumptions here. Maybe I don't want to learn the language, but am trying to solve an isolated problem while a co-worker is absent? Maybe I'm a consultant simply trying to do a proof-of-concept, and a "real coder" will do the heavy lifting? Perhaps I learned XML/XSLT 15 years ago and just need a refresher?
In any case, the solution I came up with is this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="token-value-entry">
<xsl:element name="{@token-name}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The source XML has several <token-value-entry token-name="xxx"><token-value><value>My Value</value></token-value></token-value-entry>
constructs, some of them nested within other <token-value-entry>
parent nodes.
<token-value-entry token-name="RECIPIENT_STATE">
<token-value>
<value>OR</value>
</token-value>
</token-value-entry>
<token-value-entry token-name="CNSMR_ACCNTS">
<token-value>
<list-of-values>
<token-value-entry token-name="ACCNT_CURBAL">
<token-value>
<value>.73</value>
</token-value>
My goal was to turn every instance of:
<token-value-entry token-name="SOME_VALUE">...</token-value-entry>
Into:
<SOME_VALUE>...</SOME_VALUE>
And the folks who commented and provided links got me over the conceptual hurdle. The piece I needed to re-learn was how to use variables within xsl, and now to select entire nodes rather than just the text values. Thanks.
Upvotes: 0
Reputation: 163585
Since you raised some meta-questions about how to approach the problem, let me try and address those.
I think there's a problem with your approach to learning the language. The answer is certainly not to "keep googling": on the contrary, I think you've been trying to solve your problems by googling for an answer, without ever sitting down and systematically studying the concepts of the language.
That's why you're frustrated by the process.
Your question "is there a way to use the value of an attribute as the name of a new element?" illustrates this. If you know how to use @xxx
to get the the value of an attribute, and if you know how to use xsl:element
to construct an element, then you ought to have no trouble putting the two ideas together.
If you use google and give it a description of your problem, then it will only find an answer if someone has tackled exactly the same problem and has described it in the same terms. Someone else might have tackled a slightly different problem that requires exactly the same primitives to solve it, or they might have described it in different terms, and you won't find the information. And if you do find an answer, it will probably be described in terms of concepts and terminology that you haven't mastered, because all your knowledge was acquired in random gobbets, some of it written by people who actually have very little competence.
Get yourself a good book on the language and read it, starting from the beginning and studying the examples. The author will have taken care about the order in which topics are presented so that each chapter builds on what you have learnt in previous chapters. It will teach you the building blocks that you can work with, and will give you examples of how to combine them to solve problems, some of them similar to your own, some very different.
The building blocks you need here are very simple and you are already using them, but it looks to me as if you are using them without really understanding them; I suspect you copied code that you found by googling and didn't actually understand. That's not the right strategy.
Upvotes: 0
Reputation: 117100
If you're in the context of:
<xsl:for-each select="token-value-entry">
or:
<xsl:template match="token-value-entry">
then the instruction:
<xsl:element name="{@token-name}">
<!-- content here -->
</xsl:element>
will create the desired element (provided the token-name
attribute contains a valid XML element name).
To understand how this works, read: https://www.w3.org/TR/1999/REC-xslt-19991116#attribute-value-templates.
Upvotes: 0
Reputation: 167716
Change
<xsl:template match="@token-name">
<xsl:element name="{name()}"><xsl:value-of select="."/></xsl:element>
</xsl:template>
to
<xsl:template match="token-value-entry">
<xsl:element name="{@token-name}"><xsl:value-of select="."/></xsl:element>
</xsl:template>
Upvotes: 1