How to Generate XML from Database - sql

I am fetching data from two tables CARRIER_IFTA ,IFTA_NAME.
My Select Query is like below..
SELECT t1.IFTA_LICENSE_NUMBER,t1.IFTA_BASE_STATE,t2.NAME_TYPE,t2.NAME
from CARRIER_IFTA t1 inner join IFTA_NAME t2
on t1.IFTA_LICENSE_NUMBER=t2.IFTA_LICENSE_NUMBER
My Data is coming in this way...
IFTA_LICENSE_NUMBER IFTA_BASE_STATE NAME_TYPE NAME
--------------------------------------------------------
630908333 US LG XYZ
630908333 US MG PQR
730908344 US LG ABC
Now using XSLT I want to generate XML like this
<T0019>
<IFTA_ACCOUNT>
<IFTA_LICENSE_NUMBER>630908333</IFTA_LICENSE_NUMBER>
<IFTA_BASE_STATE>US</IFTA_BASE_STATE>
<IFTA_NAME>
<NAME_TYPE>LG<NAME_TYPE>
<NAME>XYZ</NAME>
</IFTA_NAME>
<IFTA_NAME>
<NAME_TYPE>MG<NAME_TYPE>
<NAME>PQR</NAME>
<IFTA_NAME>
</IFTA_ACCOUNT>
<IFTA_ACCOUNT>
<IFTA_LICENSE_NUMBER>730908344</IFTA_LICENSE_NUMBER>
<IFTA_BASE_STATE>US</IFTA_BASE_STATE>
<IFTA_NAME>
<NAME_TYPE>LG<NAME_TYPE>
<NAME>ABC</NAME>
</IFTA_NAME>
</IFTA_ACCOUNT>
</T0019>
i have used below xslt but it is not giveng me desire result ...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="/ROWSET">
<xsl:element name="T0019">
<xsl:apply-templates select="IFTAACCOUNT"/>
</xsl:element>
</xsl:template>
<xsl:template match="IFTAACCOUNT">
<xsl:element name="IFTAACCOUNT">
<xsl:apply-templates select="IFTA_CARRIER_ID_NUMBER"/>
</xsl:element>
</xsl:template>
<xsl:template match="IFTA_LICENSE_NUMBER">
<xsl:element name="IFTA_LICENSE_NUMBER">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="IFTA_BASE_STATE">
<xsl:element name="IFTA_BASE_STATE">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="IRP_NAME">
<IRP_NAME>
<xsl:apply-templates select="NAME"/>
<xsl:apply-templates select="NAME_TYPE"/>
</IRP_NAME>
</xsl:template>
<xsl:template match="NAME">
<xsl:element name="NAME">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
<xsl:template match="NAME_TYPE">
<xsl:element name="NAME_TYPE">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
but it is not giving desire result ...
Please help me ...
Thanks in Advance...

Most RDBMS provides builtin tools to return straight XML without the need for XSL. Which one are you using? Consult its documentation. If it is for example MySQL, then you need the --xml option.

Related

Sort sequence from distinct values

What is the cleanest way to sort a sequence I get from distinct-values()? I use XPath 2.0 and my files are the following:
This is my XML file
<root>
<value>3</value>
<value>1</value>
<value>7</value>
</root>
and this is my transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="root">
<output>
<xsl:variable name="availableValues" select="distinct-values(value)"/>
<!-- now the availableValues contains the sequence (3,1,7) -->
<!-- My goal is to get this into a sorted sequence (1,3,7) -->
<!-- This is just for testing the $availableValues -->
<xsl:attribute name="count" select="count($availableValues)"/>
<xsl:for-each select="$availableValues">
<val>
<xsl:value-of select="."/>
</val>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
I have tried to use
<xsl:variable name="availableValues">
<xsl:for-each select="distinct-values(value)">
<xsl:sort/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:variable>
but this (of course) doesn't give me a sequence, just the concatenation of the values (although sorted).
EDIT:
This is what I came up so far, and it looks like a proper solution. Is there a better solution?
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xsl:output indent="yes"/>
<xsl:template match="root">
<output>
<xsl:variable name="availableValues" as="xs:integer *">
<xsl:for-each select="distinct-values(value)">
<xsl:sort/>
<xsl:sequence select="."/>
</xsl:for-each>
</xsl:variable>
<!-- This is just for testing the $availableValues -->
<xsl:attribute name="count" select="count($availableValues)"/>
<xsl:for-each select="$availableValues">
<val>
<xsl:value-of select="."/>
</val>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
Use xsl:perform-sort.
Here is an example from the link:
<xsl:perform-sort select="//BOOK">
<xsl:sort select="author/last-name"/>
<xsl:sort select="author/first-name"/>
</xsl:perform-sort>

Create a CSV from a SQL query using XSL

I need help to create a CSV file based on a SQL query.
This is how the current XSL looks like:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>
<xsl:param name="fieldNames" select="'yes'" />
<xsl:template match="NewDataSet">
<xsl:text></xsl:text>
<xsl:apply-templates select="Table"/>
</xsl:template>
<xsl:template match="Table">
<xsl:for-each select="*">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">
<xsl:value-of select="','"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Everything works fine, except the fact that I need to add a header row in the CSV with predefined values for each value. How can I do that?
This is how it looks now: enter image description here
This is how I want the CSV to look like: enter image description here
Add e.g.
<xsl:template match="/">
<xsl:text>foo,bar,baz
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
where foo,bar,baz would be your column names.

Unwrap elements with XSLT

I have large and complex documents which contain the following at various places in the document the following fragments
<a>foo<b>bar</b><a>
<a>foo<b>bar</b><b>hello</b><a>
which I want to transform to
<b>foobar<b>
<b>foobar<b><b>hello</b>
Use the following two template matchers:
<xsl:template match="a">
<xsl:apply-templates select="b"/>
</xsl:template>
<xsl:template match="b">
<xsl:copy>
<xsl:if test="position() = 1">
<xsl:value-of select="parent::a/text()"/>
</xsl:if>
<xsl:value-of select="."/>
</xsl:copy>
</xsl:template>

XSLT1 error when get first occurence of a tag

This question (and my problem) is similar to XSLT1 Get the first occurence of a specific tag... But I have an "Undefined variable" error.
I have a XML with refpos attribute, that can be make by this first XSLT,
<xsl:template match="p[#class='ref']">
<xsl:copy>
<xsl:attribute name="refpos">
<xsl:value-of select="position()"/>
</xsl:attribute>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()" name="idt">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
Then, I a main (second) XSLT I have,
<xsl:variable name="firstRef">
<xsl:value-of select="(//p[#class='ref'])[1]/#refpos"/>
</xsl:variable>
<xsl:template match="p[#refpos=$firstRef]">
<title><xsl:apply-templates /></title>
</xsl:template>
<xsl:template match="#*|node()" name="idt">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
But here this XSLT not works!!
PS: I also believe that XSLT1 allow us to do everything in one step.
XSLT 1.0 does not allow variable references in template match expressions (XSLT 2.0 does). You'll have to move the check from the predicate inside the template:
<xsl:template match="p">
<xsl:choose>
<xsl:when test="#refpos=$firstRef">
<title><xsl:apply-templates /></title>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="idt" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>

Sanitizing DB inputs with XSLT

I've been looking for a method to strip my XML content of apostrophes (') since my DBMS is complaining of receiving those.
I need
<name> Jim O'Connor</name>
to become:
<name> Jim O''Connor</name>
By looking at the example described here, that is supposed to replace ' with '', I constructed the following script:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template name="sqlApostrophe">
<xsl:param name="string" />
<xsl:variable name="apostrophe">'</xsl:variable>
<xsl:choose>
<xsl:when test="contains($string,$apostrophe)">
<xsl:value-of select="concat(substring-before($string,$apostrophe), $apostrophe,$apostrophe)"
disable-output-escaping="yes" />
<xsl:call-template name="sqlApostrophe">
<xsl:with-param name="string"
select="substring-after($string,$apostrophe)" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"
disable-output-escaping="yes" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text()">
<xsl:call-template name="sqlApostrophe">
<xsl:with-param name="string" select="."/>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
UPDATE: it works fine
Thanks for your help
The main problem is in your last template. As dacracot points out, xsl:apply-templates does not take a name attribute. To call a named template, you'd use xsl:call-template.
If you want to apply your SQL escaping to all text nodes, you could try replacing your last template with something like this:
<xsl:template match="text()">
<xsl:call-template name="sqlApostrophe">
<xsl:with-param name="string" select="."/>
</xsl:call-template>
</xsl:template>
Also, why disable-output-escaping? If the text contains special characters (<, >, &), you'll get malformed XML as the output.
You have a couple of issues syntactically...
You can't have a name attribute on an apply-templates tag.
Your xpath, "node()|#*", is ambiguous.
Have you run this through a debugger? I would suggest Oxygen.