Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Can this be done (XML to XML via XSL)?

Status
Not open for further replies.

Terrater

Technical User
Mar 18, 2008
1
DK
Hi,

I'm wondering if anybody could help me with the following?

It seems this "problem" is not trivial - at least not to me ;-)

I have this XML:

Code:
<?xml version="1.0" encoding="utf-8"?>
<dataset xmlns="[URL unfurl="true"]http://developer.cognos.com/schemas/xmldata/1/"[/URL] xmlns:xs="[URL unfurl="true"]http://www.w3.org/2001/XMLSchema-instance">[/URL]
<!--
<dataset
xmlns="[URL unfurl="true"]http://developer.cognos.com/schemas/xmldata/1/"[/URL]
xmlns:xs="[URL unfurl="true"]http://www.w3.org/2001/XMLSchema-instance"[/URL]
xs:schemaLocation="[URL unfurl="true"]http://developer.cognos.com/schemas/xmldata/1/[/URL] xmldata.xsd"
>
-->
<metadata>
<item name="Product type" type="xs:string" length="102"/>
<item name="Quantity" type="xs:int" precision="1"/>
</metadata>
<data>
<row>
<value>Binoculars</value>
<value>1075087</value>
</row>
<row>
<value>Climbing Accessories</value>
<value>5850251</value>
</row>
<row>
<value>Cooking Gear</value>
<value>13400351</value>
</row>
</data>
</dataset>

which I want to transform to the following using XSL (the number of row nodes is not fixed):

Code:
<?xml version="1.0" encoding="utf-8"?>
<data>
<row
ProductType="Binoculars"
Quantity="1075087"
/>
<row
ProductType="Climbing Accessories"
Quantity="5850251"
/>
<row
ProductType="Cooking Gear"
Quantity="13400351"
/>
</data>

Please notice that the metadata node (in the source XML) contains the names to be used in the resulting XML file as attribute names and that the name can contain one or more spaces (as indicated below in the name "Product yype").

Code:
<metadata>
<item name="[b]Product type[/b]" type="xs:string" length="102"/>
<item name="Quantity" type="xs:int" precision="1"/>
</metadata>

Another issue is that there are two <value> per <row></row> and the first of these needs to be transformed to "Product_Type" and the second needs to be transformed to "Quantity" (or whatever the <metadata> node dictates).

Thank you very much in advance...
 
>I'll say it's an issue. Quite a poor design choice.
Bad? How bad? Everything someone does not like is bad?
 
[1] The metadata should be changed to "ProductType" directly. That makes live easier and makes the design more generic, less capricious and can stand up to the test of time.

[2] This is how "without" that change. You will see specific manipulation on that metadata. That is what I meant change should be rather done there to make the xslt "more generic, less capricious". Even though it is becoming laborious, it limits its applicability to metadata name with only one space separated string, etc...
[tt]
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="[ignore][/ignore]"
xmlns="[ignore][/ignore]"
xmlns:dns="[ignore][/ignore]"
exclude-result-prefixes="dns"
>
<xsl:eek:utput method="xml" indent="yes" encoding="utf-8" />

<xsl:variable name="product_type">
<xsl:variable name="slead" select="substring-before(/dns:dataset/dns:metadata/dns:item[1]/@name,' ')" />
<xsl:variable name="strail_1" select="substring-after(/dns:dataset/dns:metadata/dns:item[1]/@name,' ')" />
<xsl:variable name="strail_11" select="substring($strail_1,1,1)" />
<xsl:variable name="strail_12" select="substring-after($strail_1,$strail_11)" />
<xsl:variable name="pre" select="concat($slead,translate($strail_11,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'),$strail_12)" />
<xsl:value-of select="translate($pre,' ','')" />
</xsl:variable>

<xsl:variable name="quantity" select="/dns:dataset/dns:metadata/dns:item[2]/@name" />
<xsl:template match="/">
<xsl:apply-templates select="dns:dataset" />
</xsl:template>
<xsl:template match="dns:dataset">
<xsl:copy>
<xsl:apply-templates select="dns:data" />
</xsl:copy>
</xsl:template>

<xsl:template match="dns:data">
<xsl:copy>
<xsl:apply-templates select="dns:row" />
</xsl:copy>
</xsl:template>
<xsl:template match="dns:row">
<xsl:copy>
<xsl:attribute name="{$product_type}">
<xsl:value-of select="dns:value[1]" />
</xsl:attribute>
<xsl:attribute name="{$quantity}">
<xsl:value-of select="dns:value[2]" />
</xsl:attribute>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>
[/tt]
[2.1] With all that labour vested into $product_type, it applies only "xxx yzzz" type of structure and the resultant attribute name becomes "xxxYzzz". Hence, it is in that sense, not at all satisfactory and non-generic. The proper course of action to take is to generate the xml with metadata with proper name attribute value being a name token compliant to spec.
 
[3] I should add that I say in terms of xslt1.0. Xslt2.0 would ease some work. Essential shortcoming remains.
 
Bad? How bad? Everything someone does not like is bad?
Tsuji, it's not a question of disliking the design. You know as well as anyone here that XML is structured, tagged data. When you create a document or part of a document where all the tags are identical without regard to the data the tags describe, the tags are meaningless: semantically void. What is the point of marking up data in a way that makes the mark-up meaningless? It's no improvement over a CSV file.
 
That makes semantics a slogan. It does not advance the science a bit.
 
This is how it is done in xslt2.0 (amend the root xsl:stylesheet to reflect that) else a complete task has to be done via recursion in xslt1.0.
[tt]
<xsl:variable name="product_type">
<xsl:variable name="name1" select="/dns:dataset/dns:metadata/dns:item[1]/@name" />
<xsl:variable name="tok" select="tokenize($name1,'\s+')" />
<xsl:for-each select="$tok">
<xsl:choose>
<xsl:when test="index-of($tok,.)!=1">
<xsl:value-of select="concat(upper-case(substring(.,1,1)),substring(.,2))" />
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="." />
</xsl:eek:therwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
[/tt]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top