XSL Replace an element by splitting it's values - xslt-1.0

I have the following XML which contains the order details in single element.
<?xml version="1.0" encoding="UTF-8"?>
<MESSAGE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MESSAGE_ID>361155</MESSAGE_ID>
<NAME>Header123</NAME>
<HEADERS>
<HEADER>
<ACTION_COUNT>1</ACTION_COUNT>
<ACTION_DESC>
<DAILY_LOAD>
<LOAD_NO>1</LOAD_NO>
<CUSTOMER_NO>09656951</CUSTOMER_NO>
<REFERENCE xsi:nil="1"/>
<SERIAL>450255470000403803</SERIAL>
<ORDERS>
<ORDER>
<ITEM>5000128762885</ITEM>
<DETAILS>4582;Robert and Co;8;5526;SWD</DETAILS>
<EMP_NO>13</EMP_NO>
<USE_BY_DATE>20110611</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
<ORDER>
<ITEM>5000128853613</ITEM>
<DETAILS>5000;Anne and Co;9;2020;ATM</DETAILS>
<EMP_NO>5</EMP_NO>
<USE_BY_DATE>20110613</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
</ORDERS>
</DAILY_LOAD>
</ACTION_DESC>
</HEADER>
</HEADERS>
<LIST_ID>23689</LIST_ID>
<TRAILER>TEST_NEEDED</TRAILER>
</MESSAGE>
I need that to be transformed into the following format.
(only the DAILY_LOAD>ORDERS section should be changed as below)
.....
<ORDERS>
<ORDER>
<ITEM>5000128762885</ITEM>
<ORDER_NO>4582</ORDER_NO>
<CUSTOMER>Robert and Co</CUSTOMER>
<NO_OF_ITEMS>8</NO_OF_ITEMS>
<TOTAL>5526</TOTAL>
<LOCATION>SWD</LOCATION>
<EMP_NO>13</EMP_NO>
<USE_BY_DATE>20110611</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
<ORDER>
<ITEM>5000128853613</ITEM>
<ORDER_NO>5000</ORDER_NO>
<CUSTOMER>Anne and Co</CUSTOMER>
<NO_OF_ITEMS>9</NO_OF_ITEMS>
<TOTAL>2020</TOTAL>
<LOCATION>ATM</LOCATION>
<EMP_NO>5</EMP_NO>
<USE_BY_DATE>20110613</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
</ORDERS>
.....
The transformed XML contains no but it's divided into CUSTOMER, NO_OF_ITEMS, TOTAL and LOCATION. Any suggestion or help will be highly appreciated.
Thank you in advance.

XSLT 1.0
Using tokenizeString template as suggested in Heber.it blog. I have modified the code for producing different tag names depending on recursion level (ORDER_NO, CUSTOMER, NO_OF_ITEMS, etc).
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!-- replaces order nodes -->
<xsl:template match="ORDER">
<ORDER>
<xsl:call-template name="tokenizeString">
<xsl:with-param name="list" select="./DETAILS"/>
<xsl:with-param name="delimiter" select="';'"/>
<xsl:with-param name="level" select="1"/>
</xsl:call-template>
</ORDER>
</xsl:template>
<!-- copy everything that doesn't match another template -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- template to tokenize strings -->
<xsl:template name="tokenizeString">
<!--passed template parameter -->
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
<xsl:param name="level"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<xsl:choose>
<xsl:when test="$level = 1">
<ITEM>
<xsl:value-of select="ITEM"/>
</ITEM>
<ORDER_NO>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</ORDER_NO>
</xsl:when>
<xsl:when test="$level = 2">
<CUSTOMER>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</CUSTOMER>
</xsl:when>
<xsl:when test="$level = 3">
<NO_OF_ITEMS>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</NO_OF_ITEMS>
</xsl:when>
<xsl:when test="$level = 4">
<TOTAL>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</TOTAL>
</xsl:when>
</xsl:choose>
<xsl:call-template name="tokenizeString">
<!-- store anything left in another variable -->
<xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
<xsl:with-param name="level" select="$level + 1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$list = ''">
<xsl:text/>
</xsl:when>
<xsl:otherwise>
<LOCATION>
<xsl:value-of select="$list"/>
</LOCATION>
<EMP_NO>
<xsl:value-of select="EMP_NO"/>
</EMP_NO>
<USE_BY_DATE>
<xsl:value-of select="USE_BY_DATE"/>
</USE_BY_DATE>
<DEPOT>
<xsl:value-of select="DEPOT"/>
</DEPOT>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0
Using tokenize function you can do this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!-- this template replaces order nodes -->
<xsl:template match="ORDER">
<ORDER>
<xsl:variable name="fields" select="tokenize(DETAILS, ';')"/>
<ITEM>
<xsl:value-of select="ITEM"/>
</ITEM>
<ORDER_NO>
<xsl:value-of select="$fields[position()=1]"/>
</ORDER_NO>
<CUSTOMER>
<xsl:value-of select="$fields[position()=2]"/>
</CUSTOMER>
<NO_OF_ITEMS>
<xsl:value-of select="$fields[position()=3]"/>
</NO_OF_ITEMS>
<TOTAL>
<xsl:value-of select="$fields[position()=4]"/>
</TOTAL>
<LOCATION>
<xsl:value-of select="$fields[position()=5]"/>
</LOCATION>
<EMP_NO>
<xsl:value-of select="EMP_NO"/>
</EMP_NO>
<USE_BY_DATE>
<xsl:value-of select="USE_BY_DATE"/>
</USE_BY_DATE>
<DEPOT>
<xsl:value-of select="DEPOT"/>
</DEPOT>
</ORDER>
</xsl:template>
<!-- this template copies everything that doesn't match another template -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Related

Validation AlphaNumeric XSLT

I was stuck with validation. i can validation when empty string, and validation with length requirement, and validation with just numeric, But when the input was have a special character and have contains alphanumeric. i was stuck. can anyone helping me correct which side i need fix with my code
MYCODE :
<?xml version="1.0" encoding="UTF-8"?>
<localEntry key="LOCAL_XSLT_Validate" xmlns="http://ws.apache.org/ns/synapse">
<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
<OperationValueRegex>
<xsl:call-template name="values">
<xsl:with-param name="vals" select="//OperationValueRegex/Value"/>
</xsl:call-template>
</OperationValueRegex>
</xsl:template>
<xsl:template name="values">
<xsl:param name="vals"/>
<xsl:choose>
<!-- Validation Number -->
<xsl:when test="fn:tokenize($vals, ' ')[matches(., '\d+')] and string-length($vals) = 8">
<Result1>
<xsl:value-of select="$vals"/>
</Result1>
</xsl:when>
<xsl:when test="$vals = 'NaN' or string-length($vals) != 8">
<Result1>
<Value>
<xsl:value-of select="$vals"/>
</Value>
<notification>input was not valid requirement maximum</notification>
</Result1>
</xsl:when>
<xsl:otherwise>
<Result1>
<Value>
<xsl:value-of select="$vals"/>
</Value>
<notification>Wrong Format</notification>
</Result1>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
</localEntry>
Request and expected result
{
"OperationValueRegex" : {
"Value" : "1234asdv"
}
}
<OperationValueRegex xmlns="http://ws.apache.org/ns/synapse" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<Result1>1234asdv</Result1>
<notification>Wrong Format</notification>
</OperationValueRegex>
Thanks
I can found the way for validation Alphanumeric
<?xml version="1.0" encoding="UTF-8"?>
<localEntry key="LOCAL_XSLT_Validate" xmlns="http://ws.apache.org/ns/synapse">
<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
<OperationValueRegex>
<xsl:call-template name="values">
<xsl:with-param name="vals" select="//OperationValueRegex/Value"/>
</xsl:call-template>
<xsl:call-template name="dates">
<xsl:with-param name="dats" select="//OperationValueRegex/Date"/>
</xsl:call-template>
</OperationValueRegex>
</xsl:template>
<xsl:template name="values">
<xsl:param name="vals"/>
<xsl:choose>
<!-- Validation Number -->
<xsl:when test="fn:matches($vals, '^\d+$') and string-length($vals) = 8">
<Result1>
<xsl:value-of select="$vals"/>
</Result1>
</xsl:when>
<xsl:when test="$vals = 'NaN' or string-length($vals) != 8">
<Result1>
<Value>
<xsl:value-of select="$vals"/>
</Value>
<notification>input was not valid requirement maximum</notification>
</Result1>
</xsl:when>
<xsl:when test="fn:matches($vals, '^[a-zA-Z0-9_]*$') and string-length($vals) > 0">
<Value>
<xsl:value-of select="$vals"/>
</Value>
<notification>Wrong Format</notification>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="dates">
<xsl:param name="dats"/>
<xsl:variable name="dateString">
<xsl:value-of select="substring($dats,1,4)"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="substring($dats,5,2)"/>
<xsl:text>-</xsl:text>
<xsl:value-of select="substring($dats,7,2)"/>
</xsl:variable>
<RequiredFormat>
<xsl:value-of select="format-date(xs:date($dateString), '[Y]/[M]/[D]')"/>
</RequiredFormat>
<OtherFormat>
<xsl:value-of select="format-date(xs:date($dateString), '[MNn] [D], [Y]')"/>
</OtherFormat>
</xsl:template>
</xsl:stylesheet>
</localEntry>
But I still have trouble with when input was have special character like = "#+./!~`*%^$()-#". Need little more help about this

Otherwise XSLT1.0 - correct output

I´ve a problem at my xslt.
Here it is:
<?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="GRP">
<xsl:copy>
<!--copy the data from ADD - ST to the GRP so it can be used in the mapping to set the delivery address from end customer-->
<xsl:for-each select ="./ADD">
<xsl:if test="./QUALIFIER='ST'">
<xsl:copy-of select="PARTY_NAME_1"/>
<xsl:copy-of select="STREET_1"/>
<xsl:copy-of select="CITY"/>
<xsl:copy-of select="POSTAL_CODE"/>
<xsl:copy-of select="COUNTRY_CODE"/>
</xsl:if>
<xsl:choose>
<xsl:when test="./QUALIFIER='CN'">
<CONTACT_NUMBER>
<xsl:value-of select="CONTACT/NUMBER"/>
</CONTACT_NUMBER>
</xsl:when>
<xsl:otherwise>
<xsl:if test="./QUALIFIER='ST'">
<CONTACT_NUMBER>
<xsl:value-of select="CONTACT/NUMBER"/>
</CONTACT_NUMBER>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<!--copy all other nodes-->
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Can you tell me, whats my mistake at my xml?
At my code i get Contact_Number 2 times.
I just like one of them... If Contact at CN - use this, otherwise use from ST.
-> If contact at CN and ST use CN.
Edit: xml:
<SEEDELFOR>
<GRP>
<ADD>
<QUALIFIER>CN</QUALIFIER>
<IDENTIFIER></IDENTIFIER>
<AGENCY_CODE></AGENCY_CODE>
<PARTY_NAME_1></PARTY_NAME_1>
<STREET_1></STREET_1>
<CITY></CITY>
<POSTAL_CODE></POSTAL_CODE>
<COUNTRY_CODE></COUNTRY_CODE>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER>1111111</NUMBER>
</CONTACT>
</ADD>
<ADD>
<QUALIFIER>ST</QUALIFIER>
<IDENTIFIER></IDENTIFIER>
<AGENCY_CODE></AGENCY_CODE>
<PARTY_NAME_1></PARTY_NAME_1>
<STREET_1></STREET_1>
<CITY></CITY>
<POSTAL_CODE></POSTAL_CODE>
<CONTACT>
<QUALIFIER></QUALIFIER>
<NUMBER>2222222</NUMBER>
</CONTACT>
</ADD>
</GRP>
</SEEDELFOR>
How can i correct my xslt?
I hope you can help me.
Best regards
Julian
One of the way you can achieve this is, rewriting the template GRP as following:
<xsl:template match="GRP">
<xsl:copy>
<!--copy the data from ADD - ST to the GRP so it can be used in the mapping
to set the delivery address from end customer -->
<xsl:variable name="contact_ST">
<xsl:for-each select="./ADD">
<xsl:if test="./QUALIFIER='ST'">
<CONTACT_NUMBER>
<xsl:value-of select="CONTACT/NUMBER" />
</CONTACT_NUMBER>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="contact_CN">
<xsl:for-each select="./ADD">
<xsl:if test="./QUALIFIER='CN'">
<CONTACT_NUMBER>
<xsl:value-of select="CONTACT/NUMBER" />
</CONTACT_NUMBER>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="./ADD">
<xsl:if test="./QUALIFIER='ST'">
<xsl:copy-of select="PARTY_NAME_1" />
<xsl:copy-of select="STREET_1" />
<xsl:copy-of select="CITY" />
<xsl:copy-of select="POSTAL_CODE" />
<xsl:copy-of select="COUNTRY_CODE" />
</xsl:if>
</xsl:for-each>
<xsl:choose>
<xsl:when test="$contact_CN != ''">
<xsl:copy-of select="$contact_CN" />
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$contact_ST" />
</xsl:otherwise>
</xsl:choose>
<!--copy all other nodes -->
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
Consider the following simplified example:
<xsl:template match="GRP">
<xsl:copy>
<!-- other code, if necessary-->
<xsl:variable name="cn" select="ADD[QUALIFIER='CN']" />
<xsl:variable name="st" select="ADD[QUALIFIER='ST']" />
<CONTACT_NUMBER>
<xsl:choose>
<xsl:when test="$cn">
<xsl:value-of select="$cn/CONTACT/NUMBER"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$st/CONTACT/NUMBER"/>
</xsl:otherwise>
</xsl:choose>
</CONTACT_NUMBER>
<!-- more code, if necessary-->
</xsl:copy>
</xsl:template>

XSL I need to remove space

I need to remove the white space between "|"
Example:
|| 3.3 | A | 001 | 2017-03-03T16:57:51 | 01 *20001000000200001437 | Only free ||
I need this output:
||3.3|A|001|2017-03-03T16:57:51|01 *20001000000200001437|Only free||
This is rather awkward to do in XSLT 1.0.
Given the following input:
XML
<root>
<item>|| 3.3 | A | 001 | 2017-03-03T16:57:51 | 01 *20001000000200001437 | Only free ||</item>
</root>
the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:copy>
<xsl:variable name="remove-left-spaces">
<xsl:call-template name="remove-spaces">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="delimiter" select="' |'"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="remove-spaces">
<xsl:with-param name="text" select="$remove-left-spaces"/>
<xsl:with-param name="delimiter" select="'| '"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="remove-spaces">
<xsl:param name="text"/>
<xsl:param name="delimiter"/>
<xsl:choose>
<xsl:when test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="remove-spaces">
<xsl:with-param name="text">
<xsl:value-of select="substring-before($text, $delimiter)"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="substring-after($text, $delimiter)"/>
</xsl:with-param>
<xsl:with-param name="delimiter" select="$delimiter"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
will return:
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>||3.3|A|001|2017-03-03T16:57:51|01 *20001000000200001437|Only free||</item>
</root>

I want substring key use on condition base

I have two param one is for separator and second is for sub
string if p then substring-before otherwise substring-after.
my Input XML .
<?xml version="1.0" encoding="iso-8859-1"?>
<results>
<result>
<Store>0180|1</Store>
</result>
<result>
<Store>0180|2</Store>
</result>
<result>
<Store>0181</Store>
</result>
<result>
<Store>0183</Store>
</result>
<result>
<Store>abc</Store>
</result>
<result>
<Store>def</Store>
</result>
<result>
<Store>0181|2</Store>
</result>
<result>
<Store>0180|3</Store>
</result>
<result>
<Store>0181|1</Store>
</result>
</results>
Xslt if fix=p then substring-before otherwise substring-after on key :
<?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:param name="name" select="'|'"/>
<xsl:param name="fix" select="'p'"/>
<xsl:choose>
<xsl:when fix='p'>
<xsl:key name="groups" match="/results/result" use="substring-before(Store,'|')" />
</xsl:when>
<otherwise>
<xsl:key name="groups" match="/results/result" use="substring-after(Store,'|')" />
</otherwise>
</xsl:choose>
<
<xsl:template match="/results">
<xsl:choose>
<xsl:when test="$fix='p'">
<xsl:apply-templates select="result[generate-id() = generate-id(key('groups', substring-before(Store,'|'))[1])]"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="result[generate-id() = generate-id(key('groups', substring-after(Store,'|'))[1])]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="result">
<xsl:choose>
<xsl:when test="$fix='p'">
<xsl:for-each select="key('groups', substring-before(Store,'|'))">
<xsl:choose>
<xsl:when test="contains(Store,'|')">
<td>
<xsl:value-of select="substring-before(Store,'|')"/>
<xsl:value-of select="'|'"/>
<xsl:value-of select="position()"/>
</td>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:value-of select="Store"/>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="key('groups', substring-before(Store,'|'))">
<xsl:choose>
<xsl:when test="contains(Store,'|')">
<td>
<xsl:value-of select="substring-after(Store,'|')"/>
<xsl:value-of select="'|'"/>
<xsl:value-of select="position()"/>
</td>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:value-of select="Store"/>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
An xsl:key definition must be at the top level of your stylesheet.
Conversely, xsl:choose cannot be at the top level.
Try this as your starting point;
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="key-direction" select="'before'"/>
<xsl:key name="key-before" match="result" use="substring-before(Store, '|')"/>
<xsl:key name="key-after" match="result" use="substring-after(Store, '|')"/>
<xsl:template match="/results">
<xsl:copy>
<xsl:choose>
<xsl:when test="$key-direction='before'">
<xsl:apply-templates select="result[generate-id()=generate-id(key('key-before', substring-before(Store,'|'))[1])]"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="result[generate-id() = generate-id(key('key-after', substring-after(Store,'|'))[1])]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
<!-- more templates -->
</xsl:stylesheet>
Note also that:
substring-before('abc', '|')
returns an empty string. This means that:
<Store>0181</Store>
and
<Store>0181|1</Store>
are not going to be grouped together, unless you replace:
substring-before(Store, '|')
with:
substring-before(concat(Store, '|'), '|')

Reading values of XML tag in variables inside XSLT

I could not find a similar question anywhere, so thats why posting this new question.
I have an XML that I want to read and convert into SQL using XSLT. The trick part is that the XML elements(i.e. the names) are not known and the XSD for the XML is generated on the fly.
But what is known is certain attributes of the elements.
The XML looks like this :
<?xml version="1.0" encoding="UTF-8"?>
<et:ItemRecordList xmlns:et="urn:org:easetech:easytest:schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:org:easetech:easytest:schema ItemRecord.xsd ">
<ItemRecord recordId="idvalue0" tableName="item_record">
<itemId columnName="item_id" idColumn="true" length="36" nullable="false">itemId</itemId>
<databaseInstitution columnName="database_institution" length="255" nullable="false">0</databaseInstitution>
<lastModifiedDate columnName="last_modified_date" length="255" nullable="false">2001-12-31T12:00:00</lastModifiedDate>
</ItemRecord>
</et:ItemRecordList>
I want to use this XML and convert it into an INSERT SQL statement using XXSLT.
I created an XSLT like this :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/">
<xsl:for-each select="/*/*">
INSERT INTO
<xsl:value-of select="#tableName" />
(
<xsl:for-each select="/*/*/*">
<xsl:variable name="columnName"><xsl:value-of select="#columnName"/></xsl:variable>
<xsl:choose>
<xsl:when test="#columnName">
<xsl:value-of select="$columnName"/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:for-each>
)
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
which gives me the output like this :
INSERT INTO item_record (item_id, database_institution, last_modified_date)
But I don't know how to create the value part of the query. The value is the value we get using
<xsl:value-of select="." />
I tried concatenating the values, but unfortunately concat didnt work for me. I also played around with xsl:variable but couldnt make it work. If someone could help me with the XSLT that I can use to create to output like below that would be really appreciated.
INSERT INTO item_record (item_id, database_institution, last_modified_date) values (itemId,0,2001-12-31T12:00:00)
How about:
<xsl:template match="/">
<xsl:for-each select="/*/*">
<xsl:text>INSERT INTO </xsl:text>
<xsl:value-of select="#tableName" />
<xsl:text> (</xsl:text>
<xsl:for-each select="*[#columnName]">
<xsl:value-of select="#columnName"/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>) values (</xsl:text>
<xsl:for-each select="*[#columnName]">
<xsl:value-of select="."/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
The next XSLT will generate the query as wanted
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:variable name="newline" select="'
'" />
<xsl:template match="/">
<xsl:apply-templates select="*/*/#tableName" />
</xsl:template>
<xsl:template match="#tableName">
<xsl:value-of select="concat('INSERT INTO ', ., ' (')" />
<xsl:apply-templates select="parent::*/*/#columnName" />
<xsl:value-of select="') VALUES ('" />
<xsl:apply-templates select="parent::*/*" mode="values" />
<xsl:value-of select="concat(')', $newline)" />
</xsl:template>
<xsl:template match="#columnName">
<xsl:choose>
<xsl:when test="position() = last()">
<xsl:value-of select="." />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(., ', ')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*" mode="values">
<xsl:choose>
<xsl:when test="position() = last()">
<xsl:value-of select="." />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(., ', ')" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>