I am using SSIS on SQL Server 2005, VS 2005 SP2.
I have created an XSLT to convert XML to CSV format. When I run this through XML Spy it works fine. I have configured an XML Task within and SSIS package to transform the XML file. Unfortunately, when SSIS performs the transform it does not include the CR/LF at the end of each record - I am left with a sigle line.
I have pased the XSLT below. Could anyone let me know why SSIS is ignoring the
?
I have also pasted a sample XML doc.
Many thanks,
Rob.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/pptxn">
<xsl:variable name="fileName" select="/pptxn/file_name"/>
<xsl:variable name="sendingOrg" select="/pptxn/sending_org"/>
<xsl:variable name="dateCreated" select="/pptxn/date_created"/>
<xsl:variable name="timeCreated" select="/pptxn/time_created"/>
<xsl:variable name="sequenceNumber" select="/pptxn/sequence_number"/>
<xsl:text>FileName,SendingOrg,DateCreated,TimeCreated,SequenceNumber,PartnerNumber,PartnerOutletRef,CardAccountNumber,TransactionDate,TransactionTime,Spend,PartnerPoints,PartnerReference,PartnerPosId</xsl:text>
<xsl:text>
</xsl:text>
<xsl:for-each select="transaction">
<xsl:value-of select="$fileName"/>,<xsl:value-of select="$sendingOrg"/>,<xsl:value-of select="$dateCreated"/>,<xsl:value-of select="$timeCreated"/>,<xsl:value-of select="$sequenceNumber"/>,<xsl:value-of select="partner_number"/>,<xsl:value-of select="partner_outlet_ref"/>,<xsl:value-of select="card_account_number"/>,<xsl:value-of select="transaction_date"/>,<xsl:value-of select="transaction_time"/>,<xsl:value-of select="spend"/>,<xsl:value-of select="partner_points"/>,<xsl:value-of select="partner_reference"/>,<xsl:value-of select="partner_pos_id"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Now the XML -->
<?xml version="1.0" encoding="UTF-8"?>
<pptxn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Y:\PartnerPoints\XML\PointsPartnerRequest.xsd">
<file_name>PPRequest.xml</file_name>
<sending_org>1</sending_org>
<date_created>20091121</date_created>
<time_created>153421</time_created>
<sequence_number>2</sequence_number>
<transaction_count>3</transaction_count>
<transaction>
<partner_number>1</partner_number>
<partner_outlet_ref>outlet ref 1</partner_outlet_ref>
<card_account_number>1</card_account_number>
<transaction_date>20091221</transaction_date>
<transaction_time>091256</transaction_time>
<spend>21.34</spend>
<partner_points>40</partner_points>
<partner_reference>shop x1</partner_reference>
<partner_pos_id>pos id 1</partner_pos_id>
</transaction>
<transaction>
<partner_number>2</partner_number>
<partner_outlet_ref>outlet ref 2</partner_outlet_ref>
<card_account_number>2</card_account_number>
<transaction_date>20091222</transaction_date>
<transaction_time>091257</transaction_time>
<spend>21.35</spend>
<partner_points>41</partner_points>
<partner_reference>shop x2</partner_reference>
<partner_pos_id>pos id 2</partner_pos_id>
</transaction>
<transaction>
<partner_number>3</partner_number>
<partner_outlet_ref>outlet ref 3</partner_outlet_ref>
<card_account_number>3</card_account_number>
<transaction_date>20091223</transaction_date>
<transaction_time>091258</transaction_time>
<spend>21.36</spend>
<partner_points>42</partner_points>
<partner_reference>shop x3</partner_reference>
<partner_pos_id>pos id 3</partner_pos_id>
</transaction>
</pptxn>
You may need to change
<xsl:text>
</xsl:text>
to
<xsl:text>
</xsl:text>
I changed the char code from hex to decimal and now it works on SSIS 2005 :)
<xsl:text>
</xsl:text>
very strange...
Related
I have a scenario where the input(source) xml is having an element which contains a valid well formed xml as string. I am trying to write an xslt that would give me the text value of that desired element which contains the payload xml. In essence, output should only be text of the element that contains it. Here is what I am trying, am I missing something obvious here. I am using xslt 1.0
Thanks.
Input xml:
<BatchOrders xmlns="http://Microsoft.ABCD.OracleDB/STMT">
<BatchOrdersRECORD>
<BatchOrdersRECORD>
<ActualPayload>
<PersonName>
<PersonGivenName>CaptainJack</PersonGivenName>
<PersonMiddleName>Walter</PersonMiddleName>
<PersonSurName>Sparrow</PersonSurName>
<PersonNameSuffixText>Sr.</PersonNameSuffixText>
</PersonName>
</ActualPayload>
</BatchOrdersRECORD>
</BatchOrdersRECORD>
</BatchOrders>
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="text()|#*" name="sourcecopy" mode="xml-to-string">
<xsl:value-of select="*"/>
</xsl:template>
<xsl:template name="xml-to-string-called-template">
<xsl:param name ="param1">
<xsl:element name ="DestPayload">
<xsl:text disable-output-escaping ="yes"><![CDATA[</xsl:text>
<xsl:call-template name ="sourcecopy"/>
<xsl:text disable-output-escaping ="yes">]]></xsl:text>
</xsl:element>
</xsl:param>
</xsl:template>
</xsl:stylesheet>
Desired Output:
<PersonName>
<PersonGivenName>CaptainJack</PersonGivenName>
<PersonMiddleName>Walter</PersonMiddleName>
<PersonSurName>Sparrow</PersonSurName>
<PersonNameSuffixText>Sr.</PersonNameSuffixText>
</PersonName>
Do you really need the mode="xml-to-string"?
Change
<xsl:template match="text()|#*" name="sourcecopy" mode="xml-to-string">
<xsl:value-of select="*"/>
</xsl:template>
to
<xsl:template match="text()|#*" name="sourcecopy">
<xsl:value-of select="." disable-output-escaping ="yes"/>
</xsl:template>
Would this template suffice?
I am newbie to XSLT.
I have a requirement to read a URL and convert some of its values into XML.
I wrote a XSLT that has to take URL as the input value and create a XML file from some of the content of the URL value.
When I debugged the XSLT in XMLSPY, I noticed that the URL value is not being picked up by inputValue variable in the below code. I am not sure if my approach to input the URL and the template match are wrong.
Any help is appreciated.
Thanks in advance.
Input to XSLT:
http://host:port/abc/xyz1/6xyz6?qq=123&pp=3
Here the XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:nnc="Nnc" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:param name="inVal" select="xs:string(http://host:port/abc/xyz1/6xyz6?qq=123&pp=3)"/>
<xsl:template match="/">
<xsl:variable name="inputValue" select="$inVal"/>
<xsl:if test="string-length($inputValue)=0">
<xsl:message terminate="yes">
inputValue is blank
</xsl:message>
</xsl:if>
<xsl:variable name="value" as="xs:string" select="substring-after($inputValue, 'abc/' )"/>
<xsl:variable name="tokenizedValues" select="tokenize($value,'/')"/>
<xsl:for-each select="$tokenizedValues">
<xsl:if test="position() = 1">
<id>
<xsl:value-of select="."/>
</id>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The desired XML output:
<?xml version="1.0" encoding="UTF-8"?>
<id>6xyz6</id>
<qq>123</qq>
<pp>123</pp>
Well if you want to pull in a text file then with XSLT 2.0 and later you can do that but not by simply using a URL, you need to call the unparsed-text function e.g.
<xsl:variable name="inputData" as="xs:string" select="unparsed-text('http://example.com/foo')"/>
See http://www.w3.org/TR/xslt20/#unparsed-text, depending on the encoding of your text document you need to add a second parameter when calling the function.
We are using XSL to convert a XML file into a pipe-delimited format.
<?xml version="1.0" encoding="UTF-8"?>
<ns:tradedata xmlns:ns="http://schemas.com/enterprise/util/extractservice/v1">
<tradedata_item>
<ORDER_ID>113632428</ORDER_ID>
<CUSIP>31393FHA7</CUSIP>
<TICKER>FHR</TICKER>
<SEC_NAME>FHR 2527 SG</SEC_NAME>
<ORDER_QTY>169249.6824</ORDER_QTY>
</tradedata_item>
<tradedata_item>
<ORDER_ID>113632434</ORDER_ID>
<CUSIP>31393G2C7</CUSIP>
<TICKER>FHR</TICKER>
<SEC_NAME>FHR 2531 ST</SEC_NAME>
<ORDER_QTY>214673.0105</ORDER_QTY>
</tradedata_item>
<tradedata_item>
<ORDER_ID>113632431</ORDER_ID>
<CUSIP>527069AH1</CUSIP>
<TICKER>LESL</TICKER>
<SEC_NAME>ZZZ_LESLIE S POOLMART INC</SEC_NAME>
<ORDER_QTY>365000.0000</ORDER_QTY>
</tradedata_item>
</ns:tradedata>
We need the first line in the output to be the column headers, and everything else would be data, like this...
ORDER_ID|CUSIP|TICKER|SEC_NAME|ORDER_QTY
1136324289|31393FHA7|FHR|FHR 2527 SG|169249.6824
1136324304|31393G2C7|FHR|FHR 2531 ST|214673.0105
We've got the XSL working to get the data, but we can't get the header to output correctly. We just select the first tradedata_item element, then iterate the element name and separate them using | characters. Here is the full XSL...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl"
version="1.0" xmlns="http://schemas.com/enterprise/util/extractservice/v1"
xmlns:o="http://schemas.com/enterprise/util/extractservice/v1" >
<!-- xsl:strip-space elements="*"/-->
<xsl:output method="text" indent="no"/>
<xsl:template match="/tradedata/tradedata_item[1]">
<xsl:for-each select="*">
<xsl:value-of select="local-name()"/>|
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="tradedata/tradedata_item">
<xsl:value-of select="ORDER_ID"/>|<xsl:value-of select="CUSIP"/>|<xsl:value-of select="TICKER"/>|<xsl:value-of select="SEC_NAME"/>|<xsl:value-of select="ORDER_QTY"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The output we're seeing is just data, no header...
113632428|31393FHA7|FHR|FHR 2527 SG|169249.6824
113632430|31393G2C7|FHR|FHR 2531 ST|214673.0105
113632431|527069AH1|LESL|ZZZ_LESLIE S POOLMART INC|365000.0000
113632434|38470RAD3|GRAHAM|ZZZ_GRAHAM PACKAGING CO|595000.0000
Please disregard any namespace inconsistencies; I had to obfuscate the xml and xsl for legal reasons.
Try this :
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="tradedata/tradedata_item[1]/*">
<xsl:value-of select="concat(name(), '|')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Output :
ORDER_ID|CUSIP|TICKER|SEC_NAME|ORDER_QTY|
It seems pretty simple to me. Maybe your error lies elsewhere.
I tried your code.. I only changed the first template to match:
<xsl:template match="//tradedata_item[1]">
and it worked for me, i.e. got the header names.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl ofi"
version="1.0" xmlns="http://schemas.com/enterprise/util/extractservice/v1"
xmlns:ofi="http://schemas.oppen.com/enterprise/util/extractservice/v1">
<xsl:output method="text" indent="no"/>
<xsl:template match="tradedata_item[position()='1']">
<xsl:for-each select="self::*">
<xsl:for-each select="child::*[position()!='5']">
<xsl:value-of select="local-name(self::*)"/>|
</xsl:for-each>
<xsl:value-of select="local-name(child::*[position()='5'])"/>
<xsl:text>
</xsl:text>
<xsl:value-of select="ORDER_ID"/>|<xsl:value-of select="CUSIP"/>|<xsl:value-of select="TICKER"/>|<xsl:value-of select="SEC_NAME"/>|<xsl:value-of select="ORDER_QTY"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:template match="tradedata_item[position()>1]">
<xsl:for-each select="self::*">
<xsl:value-of select="ORDER_ID"/>|<xsl:value-of select="CUSIP"/>|<xsl:value-of select="TICKER"/>|<xsl:value-of select="SEC_NAME"/>|<xsl:value-of select="ORDER_QTY"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I have some XML of the form:
<definitions devices="myDevice">
<reg offset="0x0000" mnem="someRegister">
<field mnem="someField" msb="31" lsb="24 />
...
</reg>
...
</definitions>
I want the XML to be the definitive reference and use XSLT to transform it to HTML for documentation, .h for building (and maybe other forms too).
The HTML version is working fine and produces a table per register, with a row per field:
... (header boilerplate removed)
<xsl:for-each select="definitions/reg">
<table>
<tr>
<th><xsl:value-of select="#offset"/></th>
<th><xsl:value-of select="#mnem"/></th>
</tr>
<xsl:for-each select="field">
<tr>
<td><xsl:value-of select="#msb"/>..<xsl:value-of select="#lsb"/></td>
<td><xsl:value-of select="#mnem"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:for-each>
Converting to a .h isn't going so well. I'm completely failing to generate the required spaces in the output:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="definitions/reg">
#define <xsl:value-of select="translate(#mnem,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
<xsl:text> </xsl:text>
<xsl:value-of select="#offset"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I'd hope for that to produce the output:
#define SOMEREGISTER 0x0000
But I actually get:
#define SOMEREGISTER0x0000
I don't understand why I get the space after the '#define', but not the one after the transformed mnemonic. I've tried a simpler solution with just an inline space, with the same results.
I'm too new to this (XSLT) to know whether I'm a) doing it wrong or b) finding a limitation in tDOM.
Testing with this:
# I could have read these from a file I suppose...
set in {<definitions devices="myDevice">
<reg offset="0x0000" mnem="someRegister">
<field mnem="someField" msb="31" lsb="24" />
</reg>
</definitions>}
set ss {<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="definitions/reg">
<xsl:text>#define </xsl:text>
<xsl:value-of select="translate(#mnem,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
<xsl:text xml:space="preserve"> </xsl:text>
<xsl:value-of select="#offset"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>}
# Interesting code starts here
package require tdom
set indoc [dom parse $in]
set xslt [dom parse -keepEmpties $ss]
set outdoc [$indoc xslt $xslt]
puts [$outdoc asText]
I find that this works. The issue is that the tDOM parser doesn't handle the xml:space attribute correctly; without the magical -keepEmpties option, all the empty strings are stripped from the stylesheet and that leads to a wrong XSLT stylesheet being applied. But with the option, it appears to do the right thing.
Note that the XSLT engine itself is doing the right thing. It's the XML parser/DOM builder. (I think it's a bug; I'll look up where to report it.)
Per:
http://www.ibm.com/developerworks/xml/library/x-tipwhitesp/index.html
Try using the preserve space directive:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="definitions/reg">
<xsl:text xml:space="preserve">#define </xsl:text>
<xsl:value-of select="translate(#mnem,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
<xsl:text xml:space="preserve"> </xsl:text>
<xsl:value-of select="#offset"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
You don't have an output method specified in your second stylesheet, so the default is gonna be XML. I'd advice you to use output method "text", then use <xsl:text> elements for any literal output. Check this example:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:for-each select="definitions/reg"><xsl:text>#define </xsl:text><xsl:value-of select="translate(#mnem,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:text> </xsl:text><xsl:value-of select="#offset"/><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
EDIT: by the way, that
at the end is a character code. It's simply the decimal value of the ASCII code for a line feed. This makes sure you start a new line for the next reg entry. If you need the Windows/DOS convention (carriage return + line feed), use
instead.
I have XML data which I have transformed using XSLT to output csv formatted text. My XSLT contains a <xsl:if test> clause to filter the result from the larger dataset of the input XML. This works but every line that is filtered out of the input is displayed as an empty line in the output.
I have tried <xsl:strip-space elements="*" /> and <xsl:template match="text()" /> but neither remove the empty lines.
A sample of my XML:
<?xml version="1.0" encoding="UTF-8"?>
<session_list xmlns="http://www.networkstreaming.com/namespaces/API" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<session lsid="fef672741e025ffda1acb3041f09252d">
<session_type>support</session_type>
<lseq>2899</lseq>
<start_time timestamp="1290027608">2010-11-17T16:00:08-05:00</start_time>
<end_time timestamp="1290027616">2010-11-17T16:00:16-05:00</end_time>
<duration>00:00:08</duration>
<public_site id="1">Default</public_site>
<external_key></external_key>
<session_chat_view_url>https://mysite.com/session_download.ns?lsid=l%3Dfef672741e025ffda1acb3041f09252d%3Bh%3D9bd6081f0b7fee08dcc32a58ef4cb54c7a0e233d%3Bt%3Dsd%3Bm%3Dchat&dl_action=chat&view=1&sessionType=sd</session_chat_view_url>
<session_chat_download_url>https://mysite.com/session_download.ns?lsid=l%3Dfef672741e025ffda1acb3041f09252d%3Bh%3D9bd6081f0b7fee08dcc32a58ef4cb54c7a0e233d%3Bt%3Dsd%3Bm%3Dchat&dl_action=chat&sessionType=sd</session_chat_download_url>
<file_transfer_count>0</file_transfer_count>
<primary_customer gsnumber="3">Smith, John</primary_customer>
<customer_list>
<customer gsnumber="3">
<username>Smith, John</username>
<public_ip>xxx.xxx.xxx.xxx</public_ip>
<private_ip>xxx.xxx.xxx.xxx</private_ip>
<hostname>DESKTOP</hostname>
<os>Windows 7 Enterprise x64 Edition (Build 7600)</os>
<primary_cust>1</primary_cust>
<info>
<name></name>
<company></company>
<company_code></company_code>
<issue></issue>
<details></details>
</info>
</customer>
</customer_list>
...etc...
</session>
</session_list>
My XSLT:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:bg="http://www.networkstreaming.com/namespaces/API" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:text>Session ID,</xsl:text>
<xsl:text>Start Time,</xsl:text>
<xsl:text>Duration,</xsl:text>
<xsl:text>Public Site,</xsl:text>
<xsl:text>Remedy Ticket Number,</xsl:text>
<xsl:text>Customer's Name,</xsl:text>
<xsl:text>Customer's Operating System,</xsl:text>
<xsl:text>Representative's Name</xsl:text>
<xsl:text>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="bg:session_list">
<xsl:apply-templates select="bg:session"/>
</xsl:template>
<xsl:template match="bg:session">
<xsl:if test="contains(bg:customer_list/bg:customer/bg:os,'Click-To-Chat')">
<xsl:value-of select="bg:lseq"/>,<xsl:text/>
<xsl:value-of select="bg:start_time"/>,<xsl:text/>
<xsl:value-of select="bg:duration"/>,<xsl:text/>
<xsl:value-of select="bg:public_site"/>,<xsl:text/>
<xsl:value-of select="bg:external_key"/>,<xsl:text/>
<xsl:value-of select="bg:primary_customer"/>,<xsl:text/>
<xsl:value-of select="bg:customer_list/bg:customer/bg:os"/>,<xsl:text/>
<xsl:value-of select="bg:primary_rep"/>
</xsl:if>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
A sample of the output:
Session ID,Start Time,Duration,Public Site,Remedy Ticket Number,Customer's Name,Customer's Operating System,Representative's Name
6488,2011-03-14T09:17:13-04:00,00:00:06,Default,,User One,Windows® (x86) Click-To-Chat,Rep1
6489,2011-03-14T09:44:50-04:00,00:39:58,Default,,Nate,Windows® (x86) Click-To-Chat,Rep1
6494,2011-03-14T10:25:23-04:00,00:03:29,Default,,User TEST,Windows® (x86) Click-To-Chat,Rep1
6498,2011-03-14T11:01:36-04:00,,Default,,User Two,Windows® (x86) Click-To-Chat,Diane
Each of the lines between the printed lines is data that was filtered out because it didn't pass the <xsl:if test="contains(bg:customer_list/bg:customer/bg:os,'Click-To-Chat')"> but the empty lines are still printed. This output doesn't look very good when opened in excel.
Does anyone have any ideas how to remove them?
Thanks!
Have you tried putting the <xsl:text>
</xsl:text> line inside the xsl:if? This is the bit that puts a newline, so at the moment you are writing one even if you don't write the line.