DataSet to write xml in groups

  • Thread starter Thread starter Victory
  • Start date Start date
V

Victory

Hi,
I have a C# dataset populated from a sql call when it writes
its xml output, it looks like:
<DocumentElement>
<cat name="something">
<firstname>myname</firstname>
</cat>
<cat name="something">
<secondname>mylastname</secondname>
</cat>
</DocumentElement>

what i need is for it to look like this:

<DocumentElement>
<cat name="something">
<item>
<firstname>myname</firstname>
</item>
<item>
<secondname>mylastname</secondname>
</item>
</cat>
</DocumentElement>

What do i need to do to make this happen?
thanks,
Mars
 
Victory said:
Hi,
I have a C# dataset populated from a sql call when it writes
its xml output, it looks like:
<DocumentElement>
<cat name="something">
<firstname>myname</firstname>
</cat>
<cat name="something">
<secondname>mylastname</secondname>
</cat>
</DocumentElement>

what i need is for it to look like this:

<DocumentElement>
<cat name="something">
<item>
<firstname>myname</firstname>
</item>
<item>
<secondname>mylastname</secondname>
</item>
</cat>
</DocumentElement>

What do i need to do to make this happen?

XSLT is a transformation language that can be used to transform XML to
XML. Microsoft support XSLT 1.0 with System.Xml.Xsl.XslCompiledTransform
and there are by now two third party XSLT 2.0 implementations that can
be used from .NET, namely Saxon 9 from http://saxon.sourceforge.net/ and
AltovaXML tools from http://www.altova.com/altovaxml.html.
Using XSLT (2.0) you could transform the format the DataSet writes out
to the format you want:

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">

<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="DocumentElement">
<xsl:copy>
<xsl:for-each-group select="cat" group-by="@name">
<cat name="{current-grouping-key()}">
<xsl:apply-templates select="current-group()/*"/>
</cat>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>

<xsl:template match="cat/*">
<item>
<xsl:copy-of select="."/>
</item>
</xsl:template>

</xsl:stylesheet>


Using XSLT 1.0 you could do it as follows:

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="k1" match="cat" use="@name"/>

<xsl:template match="DocumentElement">
<xsl:copy>
<xsl:for-each select="cat[generate-id() = generate-id(key('k1',
@name)[1])]">
<cat name="{@name}">
<xsl:apply-templates select="key('k1', @name)/*"/>
</cat>
</xsl:for-each>
</xsl:copy>
</xsl:template>

<xsl:template match="cat/*">
<item>
<xsl:copy-of select="."/>
</item>
</xsl:template>

</xsl:stylesheet>
 
Hi Martin,
I used version 2.0 of your xsl, but it produced the
following output:

<item>
<name>something</name>
</item>
<item>
<seconditemwithingroup>something</seconditemwithingroup>
</item>

i.e. it removed the <DocuemtnElement>, it removed the <cat
and it also took everything that was within the first cat
and put it into item list. I need the stuff within the cat,
all to be within one item. Items that have a matching name
in <cat name=> to be in lists of items. Here is the final
look i want to create:

<?xml version="1.0" encoding="utf-8"?>
<content>
<cat name="BEST OF 2008">
<item>
<name>Something</name>
<thumbnail>somefile</thumbnail>
<info>some info</info>
<longinfo>someother info</longinfo>
<file>some other file</file>
</item>
<item>
<name>Something</name>
<thumbnail>somefile</thumbnail>
<info>some info</info>
<longinfo>someother info</longinfo>
<file>some other file</file>
</item>
</cat>
<cat name="BEST OF 2007">
<item>
<name>Something</name>
<thumbnail>somefile</thumbnail>
<info>some info</info>
<longinfo>someother info</longinfo>
<file>some other file</file>
</item>
<item>
<name>Something</name>
<thumbnail>somefile</thumbnail>
<info>some info</info>
<longinfo>someother info</longinfo>
<file>some other file</file>
</item>
</cat>
</content>

any ideas on the xsl syntax to make this happen?
Mars
 
Victory said:
I used version 2.0 of your xsl, but it produced the
following output:

<item>
<name>something</name>
</item>
<item>
<seconditemwithingroup>something</seconditemwithingroup>
</item>

i.e. it removed the <DocuemtnElement>, it removed the <cat
and it also took everything that was within the first cat
and put it into item list.


You will need to show me the input XML and explain which XSLT processor
you used to run the stylesheet.
 
I used version 2.0, and then 1.0 and they both give the same
result. In any case, here is the xml and the expected
output:
The xml is currently like this:

<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<cat category="Wedding">
<name>diehard.png</name>

<thumbnail>/videos/special/thumbnail/diehard.png</thumbnail>
<info>This is a short description for my video</info>
<longinfo>This is a longer description for my
video.</longinfo>
<file>/videos/special/flv/livefreeordiehard-
tlr1_h640w.flv</file>
</cat>
<cat category="Wedding">
<name>rata.png</name>

<thumbnail>/videos/special/thumbnail/rata.png</thumbnail>
<info>This is the second short description for my
video</info>
<longinfo>This is the second longer description for my
video.</longinfo>
<file>/videos/special/flv/ratatouille-
tlr2_h640w.flv</file>
</cat>
</DocumentElement>

But it needs to be like:

<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<cat category="Wedding">
<item>
<name>diehard.png</name>

<thumbnail>/videos/special/thumbnail/diehard.png</thumbnail>
<info>This is a short description for my video</info>
<longinfo>This is a longer description for my
video.</longinfo>
<file>/videos/special/flv/livefreeordiehard-
tlr1_h640w.flv</file>
</item>
<item>
<name>rata.png</name>

<thumbnail>/videos/special/thumbnail/rata.png</thumbnail>
<info>This is the second short description for my
video</info>
<longinfo>This is the second longer description for my
video.</longinfo>
<file>/videos/special/flv/ratatouille-
tlr2_h640w.flv</file>
</item>
</cat>
</DocumentElement>
Mars
 
I wrote an excerpt in C# to do the transformation like this:

XslTransform xslTran = new XslTransform();
string transformPath = Server.MapPath("transform.xsl");
xslTran.Load(transformPath);

i wanted to see if there was a way without using transform
to do it. As you can see, i am using the old format and not
using the new .NET class to do the transform. but it works
just as well unless you know that the old method as i have
used here as a bug and will not work as expected. I changed
the xsl you supplied to this. Notice that the for-each-group
has a group-by that uses category as attribute rather than
name. i make a mistake before.

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="DocumentElement">
<xsl:copy>
<xsl:for-each-group select="cat" group-
by="@category">
<cat name="{current-grouping-key()}">
<xsl:apply-templates select="current-group()/*"/>
</cat>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>

<xsl:template match="cat/*">
<item>
<xsl:copy-of select="."/>
</item>
</xsl:template>

</xsl:stylesheet>

i still have the same problem.
Mars
 
This:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<!-- <xsl:strip-space elements="*"/> -->

<xsl:key name="k1" match="cat" use="@category"/>

<xsl:template match="DocumentElement">
<html>
<body>
<h2></h2>
<p><xsl:text>&lt;content&gt;</xsl:text></p>
<xsl:copy>
<xsl:for-each select="cat[generate-id() = generate-
id(key('k1', @category))[1]]">
<cat name="{@category}">
<xsl:apply-templates select="key('k1',
@category)/*"/>
</cat>
</xsl:for-each>
</xsl:copy>
<p><xsl:text>&lt;/content&gt;</xsl:text></p>
</body>
</html>
</xsl:template>

<xsl:template match="cat/*">
<item>
<xsl:copy><xsl:value-of select="node()"/></xsl:copy>
</item>
</xsl:template>

</xsl:stylesheet>

produces the following output:

<item><name>diehard.png</name></item><item><thumbnail>/video
s/special/thumbnail/diehard.png</thumbnail></item><item><inf
o>This is a short description for my
video</info></item><item><longinfo>This is a longer
description for my
video.</longinfo></item><item><file>/videos/special/flv/live
freeordiehard-
tlr1_h640w.flv</file></item><item><name>rata.png</name></ite
m><item><thumbnail>/videos/special/thumbnail/rata.png</thumb
nail></item><item><info>This is the second short description
for my video</info></item><item><longinfo>This is the second
longer description for my
video.</longinfo></item><item><file>/videos/special/flv/rata
touille-tlr2_h640w.flv</file></item>

the problem is:
I want the output to be of this format:
<content>
<cat category="something">
<item>
<name>diehard.png</name>
<thumbnail>
/videos/special/thumbnail/diehard.png
</thumbnail>
<info>
This is a short description for my video
</info>
<longinfo>
This is a longer description for my video.
</longinfo>
<file>
/videos/special/flv/livefreeordiehard-
tlr1_h640w.flv
</file>
</item>
<item>
<name>rata.png</name>
<thumbnail>
/videos/special/thumbnail/rata.png
</thumbnail>
<info>
This is the second short description for my
video
</info>
<longinfo>
This is the second longer description for my
video.
</longinfo>
<file>
/videos/special/flv/ratatouille-tlr2_h640w.flv
</file>
</item>
</cat>
... and for any additional cat of same attribute...
<cat ...>
</cat>
</content>

I can't figure out how to make the xsl to do this, yet. Any
help is appreciated.

Mars
 
Victory said:
The xml is currently like this:

<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<cat category="Wedding">
<name>diehard.png</name>

<thumbnail>/videos/special/thumbnail/diehard.png</thumbnail>
<info>This is a short description for my video</info>
<longinfo>This is a longer description for my
video.</longinfo>
<file>/videos/special/flv/livefreeordiehard-
tlr1_h640w.flv</file>
</cat>
<cat category="Wedding">
<name>rata.png</name>

<thumbnail>/videos/special/thumbnail/rata.png</thumbnail>
<info>This is the second short description for my
video</info>
<longinfo>This is the second longer description for my
video.</longinfo>
<file>/videos/special/flv/ratatouille-
tlr2_h640w.flv</file>
</cat>
</DocumentElement>

But it needs to be like:

<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<cat category="Wedding">
<item>
<name>diehard.png</name>

<thumbnail>/videos/special/thumbnail/diehard.png</thumbnail>
<info>This is a short description for my video</info>
<longinfo>This is a longer description for my
video.</longinfo>
<file>/videos/special/flv/livefreeordiehard-
tlr1_h640w.flv</file>
</item>
<item>
<name>rata.png</name>

<thumbnail>/videos/special/thumbnail/rata.png</thumbnail>
<info>This is the second short description for my
video</info>
<longinfo>This is the second longer description for my
video.</longinfo>
<file>/videos/special/flv/ratatouille-
tlr2_h640w.flv</file>
</item>
</cat>
</DocumentElement>

Here is an XSLT 1.0 stylesheet:


<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="k1" match="cat" use="@category"/>

<xsl:template match="DocumentElement">
<xsl:copy>
<xsl:for-each select="cat[generate-id() = generate-id(key('k1',
@category)[1])]">
<cat name="{@category}">
<xsl:apply-templates select="key('k1', @category)"/>
</cat>
</xsl:for-each>
</xsl:copy>
</xsl:template>

<xsl:template match="cat">
<item>
<xsl:copy-of select="*"/>
</item>
</xsl:template>

</xsl:stylesheet>

Note that this stylesheet works against the XML you posted above. That
means the root element is named 'DocumentElement'. Some of the XML you
posted had a root element of a different name, in that case
<xsl:template match="DocumentElement">
would not match.
 
Martin,
That works except that whatever i do to try to wrap this in a
<content> tag like this, it does not work:

<content>
<item>
</item>
<item>
</item>
</content>

i have tried <xsl:text>&lt;content&gt;<xsl:text> but it does
not get written to the output. Any ideas?
thanks,
Mars
 
Victory said:
That works except that whatever i do to try to wrap this in a
<content> tag like this, it does not work:

<content>
<item>
</item>
<item>
</item>
</content>

The stylesheet I posted creates the following output:

<DocumentElement>
<cat name="Wedding">
<item>
<name>diehard.png</name>
<thumbnail>/videos/special/thumbnail/diehard.png</thumbnail>
<info>This is a short description for my video</info>
<longinfo>This is a longer description for my video.</longinfo>
<file>/videos/special/flv/livefreeordiehard-tlr1_h640w.flv</file>
</item>
<item>
<name>rata.png</name>
<thumbnail>/videos/special/thumbnail/rata.png</thumbnail>
<info>This is the second short description for my video</info>
<longinfo>This is the second longer description for my
video.</longinfo>
<file>/videos/special/flv/ratatouille-tlr2_h640w.flv</file>
</item>
</cat>
</DocumentElement>

Which elements exactly do you want to wrap into an element named 'content'?
 
I am sorry, i meant to replace DocumentElement with content.
Also, right now, the cat tags are not in the output. only
the items, this is the output i get right now with your
latest xsl:

<item>
<name>diehard.png</name>

<thumbnail>/videos/special/thumbnail/diehard.png</thumbnail>
<info>This is a short description for my video</info>
<longinfo>This is a longer description for my
video.</longinfo>
<file>/videos/special/flv/livefreeordiehard-
tlr1_h640w.flv</file>
</item>
<item>
<name>rata.png</name>
<thumbnail>/videos/special/thumbnail/rata.png</thumbnail>
<info>This is the second short description for my
video</info>
<longinfo>This is the second longer description for my
video.</longinfo>
<file>/videos/special/flv/ratatouille-
tlr2_h640w.flv</file>
</item>

It is supposed to be like:

<DocumentElement>
<cat category="something">
<item>
...
</item>
<item>
...
</item>
</cat>
</DocumentElement>

How do i make it so it outputs the cat as well as the
DocuementElement tags. I also intend to replace the
DocumentElement with the word content.
thank you,
Mars
 
Victory said:
I am sorry, i meant to replace DocumentElement with content.
Also, right now, the cat tags are not in the output. only
the items, this is the output i get right now with your
latest xsl:

<item>
<name>diehard.png</name>

<thumbnail>/videos/special/thumbnail/diehard.png</thumbnail>
<info>This is a short description for my video</info>
<longinfo>This is a longer description for my
video.</longinfo>
<file>/videos/special/flv/livefreeordiehard-
tlr1_h640w.flv</file>
</item>
<item>
<name>rata.png</name>
<thumbnail>/videos/special/thumbnail/rata.png</thumbnail>
<info>This is the second short description for my
video</info>
<longinfo>This is the second longer description for my
video.</longinfo>
<file>/videos/special/flv/ratatouille-
tlr2_h640w.flv</file>
</item>

Somehow the XML you are running the stylesheet against is not the XML
you have posted. Otherwise I can't explain why you do not get the
correct result.
When I transform

<DocumentElement>
<cat category="Wedding">
<name>diehard.png</name>

<thumbnail>/videos/special/thumbnail/diehard.png</thumbnail>
<info>This is a short description for my video</info>
<longinfo>This is a longer description for my video.</longinfo>
<file>/videos/special/flv/livefreeordiehard-tlr1_h640w.flv</file>
</cat>
<cat category="Wedding">
<name>rata.png</name>

<thumbnail>/videos/special/thumbnail/rata.png</thumbnail>
<info>This is the second short description for my video</info>
<longinfo>This is the second longer description for my
video.</longinfo>
<file>/videos/special/flv/ratatouille-tlr2_h640w.flv</file>
</cat>
</DocumentElement>

with the stylesheet

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="k1" match="cat" use="@category"/>

<xsl:template match="DocumentElement">
<xsl:copy>
<xsl:for-each select="cat[generate-id() = generate-id(key('k1',
@category)[1])]">
<cat name="{@category}">
<xsl:apply-templates select="key('k1', @category)"/>
</cat>
</xsl:for-each>
</xsl:copy>
</xsl:template>

<xsl:template match="cat">
<item>
<xsl:copy-of select="*"/>
</item>
</xsl:template>

</xsl:stylesheet>

then the result is

<DocumentElement>
<cat name="Wedding">
<item>
<name>diehard.png</name>
<thumbnail>/videos/special/thumbnail/diehard.png</thumbnail>
<info>This is a short description for my video</info>
<longinfo>This is a longer description for my video.</longinfo>
<file>/videos/special/flv/livefreeordiehard-tlr1_h640w.flv</file>
</item>
<item>
<name>rata.png</name>
<thumbnail>/videos/special/thumbnail/rata.png</thumbnail>
<info>This is the second short description for my video</info>
<longinfo>This is the second longer description for my
video.</longinfo>
<file>/videos/special/flv/ratatouille-tlr2_h640w.flv</file>
</item>
</cat>
</DocumentElement>
 
Yes, you are correct. I changed the <DocumentElement> to <NewDataSet>
and it works now! The beginning tag changed when i switch to using
transform and that is why the <cat tag was not outputted and only the
item and its contents where outputted. At some point, i though i change
the file to have it to start out with the words <content> but i changed
my mind on that.
Thanks a lot!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Mars
 
Back
Top