XSLT 3.0 Identity transform document collection? - java

I have one XSLT 3.0:
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:n1="urn:hl7-org:v3">
<xsl:output indent="yes" method="xml" encoding="utf-8"/>
<xsl:param name="icd10Map" as="map(xs:string, xs:string)"
select="
map {
'1742': 'C502',
'55090': 'K409',
'8442': 'S8350',
'7172': 'M2332',
'36616': 'H251',
'4550': 'K648'
}"/>
<xsl:variable name="map-keys" select="map:keys($icd10Map)"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="n1:translation[#codeSystemName = 'ICD-9-CM']/#code">
<xsl:attribute name="code">
<xsl:value-of select="$icd10Map($map-keys[translate(normalize-space(current()), '
.;', '') = .])"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
One input XML:
<?xml-stylesheet type="text/xsl" href="./Content/xsl/CDA.xsl"?>
<ClinicalDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:hl7-org:v3 NIST_C32_schema/C32_CDA.xsd" xmlns="urn:hl7-org:v3" xmlns:sdtc="urn:hl7-org:sdtc">
<realmCode code="US" />
<typeId root="2.16.840.1.113883.1.3" extension="POCD_HD000040" />
<templateId root="2.16.840.1.113883.10.20.22.1.1" />
************************************************************
<id extension="TT988" root="2.16.840.1.113883.19.5.99999.1" />
<code codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" code="11504-8" displayName="Surgical Operation Note" />
<title>Operative Report</title>
****************************************************
<component>
<structuredBody>
<component>
<section>
***********************
<entry>
<act moodCode="EVN" classCode="ACT">
<templateId root="2.16.840.1.113883.10.20.22.4.65" />
<code code="10219-4" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="Preoperative Diagnosis" />
<entryRelationship typeCode="SUBJ">
<observation classCode="OBS" moodCode="EVN">
<code code="282291009" displayName="Diagnosis" codeSystem="2.16.840.1.113883.6.96" codeSystemName="SNOMED CT" />
<statusCode code="completed" />
<!-- ICD-9 be transformed to ICD-10 -->
<value nullFlavor="OTH" type="CD">
<translation code="366.16" displayName="Nuclear sclerosis" codeSystem="2.16.840.1.113883.6.103" codeSystemName="ICD-9-CM" />
</value>
</observation>
</entryRelationship>
</act>
</entry>
</section>
</component>
</structuredBody>
</component>
</ClinicalDocument>
The transformation scenario in Oxygen with just one document is without issue:
*******************
<value nullFlavor="OTH" type="CD">
<translation code="H251"
displayName="Nuclear sclerosis"
codeSystem="2.16.840.1.113883.6.103"
codeSystemName="ICD-9-CM"/>
</value>
******************
However, XSLT 3.0 identity transform for collection seems working like this:
<xsl:variable name="inFile" as="node()*" select="collection('hl7.xml')"/>
<xsl:template match="/">
<xsl:text>
ICD9 Target Transformation in the collection is:
</xsl:text>
<xsl:for-each select="$inFile//n1:translation[#codeSystemName = 'ICD-9-CM']/#code">
<xsl:value-of select="$icd10Map($map-keys[translate(normalize-space(current()), '
.;', '') = .])" separator=" , "/>
</xsl:for-each>
</xsl:template>
Result:
ICD9 Target Transformation in the collection is:
H251
H251
K648
K648
K409
K409
S8350
M2332
M2332
S8350
If I change the XSLT to:
<xsl:mode on-no-match="shallow-copy"/>
<xsl:variable name="inFile" as="node()*" select="collection('hl7.xml')"/>
<xsl:template match="n1:translation[#codeSystemName = 'ICD-9-CM']/#code">
<xsl:text>
ICD9 Target Transformation in the collection is:
</xsl:text>
<xsl:for-each select="$inFile">
<xsl:attribute name="code">
<xsl:value-of select="$icd10Map($map-keys[translate(normalize-space(current()), '
.;', '') = .])" separator=" , "/>
</xsl:attribute>
</xsl:for-each>
</xsl:template>
It doesn’t appear any transform happen and is merely an extraction of the URI list in the catalog file hl7.xml.
I develop a Java application which can bulk validate documents against XSD, transform (without collection()) and finally write the documents into database. The logging is the desired result:
Engine Instantiation: com.fc.andante.sax.SAXValidateStreamTransformWrite
Schema Validation Status: files in:/ml/Andante/data/data are validated against schema file:/ml/Andante/data/operation-transform.xsd
User 'auditor' has validated files in:/ml/Andante/data/data on 2020-08-26T23:05:26.357431
*****************
Transaction Status: Authenticating database writer...
Transaction Status: User audited as 'super' is transforming document set...
Transaction Status: Document data/data/cataract.xml is successfully transformed and written into database with uri '/xslt-transform/cataract.xml'
Transaction Status: Document data/data/breast-surgery.xml is successfully transformed and written into database with uri '/xslt-transform/breast-surgery.xml'
Transaction Status: Document data/data/hernia.xml is successfully transformed and written into database with uri '/xslt-transform/hernia.xml'
Transaction Status: Document data/data/colonoscopy.xml is successfully transformed and written into database with uri '/xslt-transform/colonoscopy.xml'
Transaction Status: Document data/data/knee.xml is successfully transformed and written into database with uri '/xslt-transform/knee.xml'
Die Transaktion wurde erfolgreich abgeschlossen 2020-08-26T23:05:28.341385700
Can anyone help to solve the XSLT 3.0 Collections transform issue?

I would use a global parameter
<xsl:param name="inFiles" as="document-node()*" select="collection('hl7.xml')"/>
and then start processing with a named template
<xsl:template name="xsl:initial-template">
<xsl:for-each select="$inFiles">
<xsl:result-document href="/xslt-transform/{tokenize(document-uri(), '/')[last()]}">
<xsl:apply-templates/>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
Then you can xsl:import your first XSLT sample from the question or of course edit it to insert the code I have shown. Make sure you let Saxon start with the named template (-it command line option for Saxon; in oXygen by not providing a source document).

Related

Transform XML to CSV with Saxon = error: Output character 160

I am try to transform from XML (UTF-8 encoding) to CSV (win-1251 encoding) - I get an error
net.sf.saxon.trans.DynamicError: Output character not available in this encoding (decimal 160)
I understand that in the xml text there is a character with code 160 which is not in win-1251.
Tried to clear XML before transformation process, but it doesn't help
Charset charset = Charset.forName("windows-1251");
CharsetDecoder decoder = charset.newDecoder();
CharsetEncoder encoder = charset.newEncoder();
encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
String result = s;
try {
ByteBuffer bbuf = encoder.encode(CharBuffer.wrap(s));
CharBuffer cbuf = decoder.decode(bbuf);
result = cbuf.toString();
} catch (CharacterCodingException cce) {
log.error("Exception during character encoding/decoding: " + cce.getMessage());
}
Please tell me the best way to solve this problem?
my xsl sample
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE csv-style [
<!ENTITY semicolons ';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;'>
<!ENTITY commas ',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,'>
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" >
<xsl:output method="text" indent="no" omit-xml-declaration="yes" encoding="windows-1251"/>
<xsl:param name="delim">semicolon</xsl:param>
<xsl:param name="showHead">yes</xsl:param>
<xsl:variable name="delimStr">
<xsl:choose>
<xsl:when test="$delim = 'comma'">&commas;</xsl:when>
<xsl:otherwise>&semicolons;</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:template match="blocks">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="description|pair|foot|body/table/head">
<!-- don't do anything just skip it-->
</xsl:template>
<xsl:template match="table">
<xsl:apply-templates select="table|head|body"/>
</xsl:template>
<xsl:template match="col">
<xsl:if test="position()=1">
<xsl:value-of select="substring($delimStr, 1, #id - 1)"/>
</xsl:if>
<xsl:choose>
<xsl:when test="#value">
<xsl:text>"</xsl:text><xsl:variable name="escape">
<xsl:call-template name="_replace_string">
<xsl:with-param name="string" select="#value" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$escape" /><xsl:text>"</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>""</xsl:text>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="position()=last()">
<xsl:value-of select="substring($delimStr, 1, ancestor::table[1]/#colNum - #id)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($delimStr, 1, following-sibling::col[1]/#id - #id)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template> <!-- col -->
<xsl:template match="row">
<xsl:if test="col[#value][1]">
<xsl:apply-templates select="col"/>
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="head">
<xsl:if test="$showHead = 'yes'">
<xsl:apply-templates select="*"/>
</xsl:if>
</xsl:template>
<xsl:template match="body">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template name="_replace_string">
<xsl:param name="string" select="''"/>
<xsl:variable name="find">"</xsl:variable>
<xsl:variable name="replace">""</xsl:variable>
<xsl:choose>
<xsl:when test="contains($string,$find)">
<xsl:value-of select="concat(substring-before($string,$find),$replace)"/>
<xsl:call-template name="_replace_string">
<xsl:with-param name="string" select="substring-after($string,$find)"/>
<xsl:with-param name="find" select="$find"/>
<xsl:with-param name="replace" select="$replace"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
my xml sample
<?xml version="1.0" encoding="UTF-8" ?><blocks type="report"><functions><func num="4" text=" nameOf_10031"></func><func num="5" text="name Of_10071"></func><func num="6" text="name Of_10006"></func></functions><description name="[441] testesttest with 160 "><rows total="44" start="1" end="44" show-data="yes"></rows><columns count="10"><column id="1" type="4" position="1" width="" format="&apos;dd.mm.yyyy&apos;"></column><column id="2" type="4" position="2" width="" format="&apos;dd.mm.yyyy&apos;"></column><column id="3" type="3" position="3" width=""></column><column id="4" type="2" position="4" width=""></column><column id="5" type="2" position="5" width=""></column><column id="6" type="2" position="6" width=""></column><column id="7" type="2" position="7" width=""></column><column id="8" type="2" position="8" width=""></column><column id="9" type="2" position="9" width=""></column><column id="10" type="2" position="10" width=""></column></columns></description><pair name="ReportName" value="test test test "></pair><table colNum="10" id="12561"><head><row><col id="1" value="test test test"></col><col id="2" value=" test test test"></col><col id="3" value="test test test"></col><col id="4" value="test test test"></col><col id="5" value="test test test"></col><col id="6" value="test test test"></col><col id="7" value="test test test"></col><col id="8" value=" test test test"></col><col id="9" value="test test test"></col><col id="10" value="test test test"></col></row></head><body><row num="1"><col id="1" value="01.07.2006"></col><col id="2"></col><col id="3" value="53363"></col><col id="4" value="65187" record-id="65187"></col><col id="5" value="53363" record-id="53368"></col><col id="6" value="test test test" record-id="1974"></col><col id="7"></col><col id="8"></col><col id="9" value="test test test"></col><col id="10"></col></row></body></table></blocks>
when i try
java -cp saxon-9.1.0.8.jar net.sf.saxon.Transform -t -s:myxml.xml -xsl:myxsl.xsl -o:result.csv
i get an same error (160)
Saxon 9.1.0.8J from Saxonica
Java version 1.8.0_333
Warning: at xsl:stylesheet on line 11 column 81 of myxsl.xsl:
Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor
Stylesheet compilation time: 378 milliseconds
Processing file:/D:/111/myxml2.xml
Building tree for file:/D:/111/myxml2.xml using class net.sf.saxon.tinytree.TinyBuilder
Tree built in 4 milliseconds
Tree size: 46 nodes, 0 characters, 99 attributes
Loading net.sf.saxon.event.MessageEmitter
Error at xsl:value-of on line 46 of myxsl.xsl:
Output character not available in this encoding (decimal 160)
at xsl:apply-templates (file:/D:/111/myxsl.xsl#66)
processing /blocks/table[1]/head[1]/row[1]/col[2]
at xsl:apply-templates (file:/D:/111/myxsl.xsl#73)
processing /blocks/table[1]/head[1]/row[1]
at xsl:apply-templates (file:/D:/111/myxsl.xsl#32)
processing /blocks/table[1]/head[1]
at xsl:apply-templates (file:/D:/111/myxsl.xsl#24)
processing /blocks/table[1]
in built-in template rule
Transformation failed: Run-time errors were reported
When I use a newer version, for example Saxon-HE-10.3.jar, there are no problems, but unfortunately I can't upgrade to it
A character map mapping e.g the non-breaking space 160 to a normal space 32 would be
<xsl:character-map name="m1">
<xsl:output-character character=" " string=" "/>
</xsl:character-map>
<xsl:output use-character-maps="m1"/>
Character maps are supported since XSLT 2 and Saxon 8.9 I think was the first version to implement the 2.0 standard so 9.1 should cover that.
You are using a very old (and unsupported) version of Saxon. In Saxon 9.1 (released in 2009) the software maintained its own data tables for character encoding, rather than getting it all from the JDK. According to the definition of CP1251 used in the Saxon 9.1 data tables, there is no mapping for the Unicode codepoint 160. The relevant source code contains a link to the URI http://www.microsoft.com/globaldev/reference/sbcs/1251.htm as its source of information, but that web page is no longer available.
Sorry we can't help you more, but this kind of thing happens if you don't upgrade your software from time to time.
Your best way forward is probably to output the data in UTF-8 encoding and then use some other utility to convert the CSV file from UTF-8 to CP1251.

Converting unusual XML data to CSV through XSLT

<?xml version="1.0" encoding="UTF-8"?>
<FirstTag version="1.0" createTime="15:59:59" DATE="20161209">
<SecondTag Name="House01">
<a>
<Furniture FURN_ID="FUR00001" FURN_AMT="2" price="10000"/>
<Furniture FURN_ID="FUR00002" FURN_AMT="1" price="20000"/>
</a>
<b>
<Furniture FURN_ID="FUR00003" FURN_AMT="2" price="30000"/>
<Furniture FURN_ID="FUR00004" FURN_AMT="1" price="40000"/>
</b>
<c>
<Furniture FURN_ID="FUR00005" FURN_AMT="2" price="50000"/>
<Furniture FURN_ID="FUR00006" FURN_AMT="1" price="60000"/>
</c>
<d>
<Furniture FURN_ID="FUR00007" FURN_AMT="1" price="70000"/>
<Furniture FURN_ID="FUR00008" FURN_AMT="1" price="80000"/>
</d>
<e>
<Furniture FURN_ID="FUR00009" FURN_AMT="1" price="90000"/>
<Furniture FURN_ID="FUR00010" FURN_AMT="1" price="100000"/>
</e>
<f>
<Furniture FURN_ID="FUR00011" FURN_AMT="1" price="110000"/>
<Furniture FURN_ID="FUR00012" FURN_AMT="2" price="120000"/>
<Furniture FURN_ID="FUR00013" FURN_AMT="2" price="120000"/>
</f>
</SecondTag>
</FirstTag>
Above is the simple xml (with node value), that I produced from my Java program. The point is, I want to send this xml data to another application, where there's already a csv load function from the UI/batch processes. I've heard of XSLT but never use of it, tried some of the tutorial but got confused in the time to get all the values into a csv.
Here's what it should look like in csv (to start, after success need to do some calculation):
In this example in one house (HOUSE01) I would like to output all the furniture in different room (i.e. a is room 1, b is room 2, c is room 3, etc).
I've been trying to build the XSLT, below is the XSLT:
<?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" />
<xsl:variable name="delimiter" select="','" />
<!-- define an array containing the fields we are interested in -->
<xsl:variable name="fieldArray">
<field>Name</field>
<field>a</field>
<field>b</field>
<field>c</field>
<field>d</field>
<field>e</field>
<field>f</field>
</xsl:variable>
<xsl:param name="fields" select="document('')/*/xsl:variable[#name='fieldArray']/*" />
<xsl:template match="/">
<!-- output the header row -->
<xsl:for-each select="$fields">
<xsl:if test="position() != 1">
<xsl:value-of select="$delimiter"/>
</xsl:if>
<xsl:value-of select="." />
</xsl:for-each>
<!-- output newline -->
<xsl:text>
</xsl:text>
<xsl:apply-templates select="/*/*"/>
</xsl:template>
<xsl:template match="a">
<xsl:variable name="currNode" select="." />
<!-- output the data row -->
<!-- loop over the field names and find the value of each one in the xml -->
<xsl:for-each select="$fields">
<xsl:if test="position() != 1">
<xsl:value-of select="$delimiter"/>
</xsl:if>
<xsl:value-of select="$currNode/*[name() = current()]/#FURN_ID" />
<!-- <xsl:value-of select="$currNode/*[name() = current()]" /> -->
</xsl:for-each>
<!-- output newline -->
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
I'm using some reference from another page, and can build some simple XSLT to transform XML to CSV, however, I need some guidance in order to solve my main XML issue. In the future after I can get the node value inside the loop, I'd like to sum the total price of every furniture for each room.
Expected final csv result:
Name,a,b,c,d,e,f
House01,40000,100000,160000,150000,190000,350000
Thank you.
Getting the value of an attribute in XML
This XSLT will give the output you specified. See demo.
Updated: I missed the a value in the output.
<?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" />
<xsl:template match="/">
<xsl:text>Name,a,b,c,d,e,f
</xsl:text>
<xsl:apply-templates select="FirstTag/SecondTag/a/Furniture"/>
</xsl:template>
<xsl:template match="Furniture">
<xsl:variable name="pos" select="position()"/>
<xsl:value-of select="../../#Name"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="#FURN_ID"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="../../b/Furniture[position()=$pos]/#FURN_ID"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="../../c/Furniture[position()=$pos]/#FURN_ID"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="../../d/Furniture[position()=$pos]/#FURN_ID"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="../../e/Furniture[position()=$pos]/#FURN_ID"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="../../f/Furniture[position()=$pos]/#FURN_ID"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
The second (final) .csv can be produced as follows:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/FirstTag">
<!-- first pass -->
<xsl:variable name="values-rtf">
<xsl:for-each select="SecondTag/*">
<xsl:copy>
<xsl:for-each select="Furniture">
<value>
<xsl:value-of select="#FURN_AMT * #price"/>
</value>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="values" select="exsl:node-set($values-rtf)/*" />
<!-- header -->
<xsl:text>Name,</xsl:text>
<xsl:for-each select="$values">
<xsl:value-of select="name()"/>
<xsl:if test="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<!-- summary -->
<xsl:value-of select="SecondTag/#Name"/>
<xsl:text>,</xsl:text>
<xsl:for-each select="$values">
<xsl:value-of select="sum(value)"/>
<xsl:if test="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This assumes you are limited to XSLT 1.0; in XSLT 2.0 this could be done in a single pass.
Note that I am assuming the input XML will contain a single "house" (SecondTag), with a variable number of "rooms" (a, b, c, etc.). Otherwise it's not clear what the header of the .csv should be.
I am not sure if you need to also have the interim .csv - and in any case, the logic required to create it is not clear (why is FUR00013 missing from the output?).

Coloring occasional lines in full XML Structure and show in HTML

My First question is marked as duplicated, but it isn't a duplicate
show XML in HTML with inline stylesheet
I hope this question is not immediatley marked as duplicate, only because one of the moderators has read the first two sentences and've ignored the rest.
The Problem is not to show an XML Structure in HTML, rather to show a full dynamically XML structure, with all tags and occasional colored lines.
The structure and interior fields are full dynamically and every field can be correct or wrong, depending on the xml file like to compare.
So a field is at the first comparison correct, but on another comparison it’s wrong. The fields and structure of XML can vary greatly from one comparison to another.
I’m looking since yesterday for a corresponding and professional solution for this problem.
Background process: comparison different xml files, via soa microservices in java. The comparison is made by org.custommonkey.xmlunit. The Result have to be an html popup, what shows me differences marked by colored lines.
Example Output XUnit Diff Result XPath
/ROOT[1]/MATDETAIL[1]/OUTPUT[1]/GENERAL[1]/CHANGED_BY[1]/text()[1]
Transform the source xml via xslt and the xunit diff result informations.
Example Input XML
<ROOT>
<MATDETAIL>
<OUTPUT>
<GENERAL>
<CREATED_ON/>
<CREATED_BY>ORIGINAL USER</CREATED_BY>
<LAST_CHNGE/>
<CHANGED_BY>NEW USER</CHANGED_BY>
</GENERAL>
<RETURN>
<TYPE>S</TYPE>
<MESSAGE/>
<LOG_NO/>
<LOG_MSG_NO>000000</LOG_MSG_NO>
</RETURN>
</OUTPUT>
</MATDETAIL>
</ROOT>
Example XSL Transformation
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*" mode="unescape"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/ROOT[1]/MATDETAIL[1]/OUTPUT[1]/GENERAL[1]/CHANGED_BY[1]">
<xsl:element name = "span">
<xsl:attribute name="style">font-weight:bold; color:red </xsl:attribute>
<xsl:copy>
<xsl:value-of select = "current()" />
</xsl:copy>
<xsl:text><== Expected: dasda</xsl:text>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Example Result of XSL Transformation
<ROOT>
<MATDETAIL>
<OUTPUT>
<GENERAL>
<CREATED_ON/>
<CREATED_BY>ORIGINAL USER</CREATED_BY>
<LAST_CHNGE/>
<span style="font-weight:bold; color:red "><CHANGED_BY>NEW USER</CHANGED_BY><== Expected: ORIGINAL USER</span>
</GENERAL>
<RETURN>
<TYPE>S</TYPE>
<MESSAGE/>
<LOG_NO/>
<LOG_MSG_NO>000000</LOG_MSG_NO>
</RETURN>
</OUTPUT>
</MATDETAIL>
</ROOT>
I’m not able to show this xml structure in html, with (all) tags, correctly AND colored.
Either I’ve get no tags, so there are only the raw data in XML to see, without tags, but the lines are colored.
Or I get the xml structure with all data, but not colored.
I tried to replace the lt and gt chars inside xslt, but failed, or after transformation in java, this result shows very ugly. My colleague has meant that we can not use it in any way.
Because the XML Structur can be every time different and so on fully dynamically, I can not style the xml with css and tag definition.
Unfortunately, alternative implementations are not an option. I have to do this somehow with the means available to me. (Java, XML & XSL, JS, HTML, CSS).
I hope to get good ideas to solute this.
I would like to thank you in advance.
I hope i can solve your issue with following try.
I. Input:
<ROOT baum="baum">
<MATDETAIL>
<OUTPUT>
<GENERAL>
<CREATED_ON/>
<CREATED_BY>ORIGINAL USER</CREATED_BY>
<LAST_CHNGE/>
<CHANGED_BY>NEW USER</CHANGED_BY>
</GENERAL>
<RETURN>
<TYPE>S</TYPE>
<MESSAGE/>
<LOG_NO/>
<LOG_MSG_NO>000000</LOG_MSG_NO>
</RETURN>
</OUTPUT>
</MATDETAIL>
</ROOT>
II. Stylesheet (XSLT 1.0):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="CHANGED_BY">
<span style="color:red;">
<xsl:apply-templates select="." mode="serialize"/>
</span>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates select="." mode="serialize"/>
</xsl:template>
<xsl:template match="#*">
<xsl:apply-templates select="." mode="serialize"/>
</xsl:template>
<xsl:template match="*" mode="serialize">
<xsl:value-of select="concat('<', name())"/>
<xsl:apply-templates select="#*" />
<xsl:choose>
<xsl:when test="node()">
<xsl:text>></xsl:text>
<xsl:apply-templates />
<xsl:value-of select="concat('<', name(), '>')"/>
</xsl:when>
<xsl:otherwise>
<xsl:text> /></xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="#*" mode="serialize">
<xsl:value-of select="concat(' ', name(), '="', ., '"')"/>
</xsl:template>
<xsl:template match="text()" mode="serialize">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
III: Output:
<ROOT baum="baum">
<MATDETAIL>
<OUTPUT>
<GENERAL>
<CREATED_ON />
<CREATED_BY>ORIGINAL USER</CREATED_BY>
<LAST_CHNGE />
<span style="color:red;"><CHANGED_BY>NEW USER</CHANGED_BY></span>
</GENERAL>
<RETURN>
<TYPE>S</TYPE>
<MESSAGE />
<LOG_NO />
<LOG_MSG_NO>000000</LOG_MSG_NO>
</RETURN>
</OUTPUT>
</MATDETAIL>
</ROOT>
IV. Explanation:
Whenever the mode="serialize" is applied, the context is escaped. See example for CHANGED_BY to format with HTML-Tags. The xml structure is fully escaped so the browser shows it like a string instead of tags.
I really hope it solves your problem

How can I join 2 XML in 1 XSL

I have two .xml files which need to be joined
The first file is Song.xml as the following:
<Songs>
<Song>
<SongID>1</SongID>
<SongName>We dont talk anymore</SongName>
<Author>M-TP</Author>
<UploadBy>admin</UploadBy>
<GerneCode>1</GerneCode>
</Song>
</Songs>
and the Gerne.xml which generate from a schema
<ns2:gernes xmlns="http://www.w3.org/2001/XMLSchema/playlist" xmlns:ns2="https://xml.netbeans.org/schema/genses">
<ns2:gerne>
<GerneCode>1</GerneCode>
<GerneName>Pop</GerneName>
<Image>img-pop.jpg</Image>
</ns2:gerne>
</ns2:gerne>
I want to join these .xml files inside a XSL, to which will add the GerneName for every Song that match the GerneName inside the Gerne.xml.
The result im trying to get should be like this:
<Songs>
<Song>
<SongID>1</SongID>
<SongName>We dont talk anymore</SongName>
<Author>M-TP</Author>
<UploadBy>admin</UploadBy>
<GerneName>Pop</GerneName>
<GerneCode>1</GerneCode>
</Song>
</Songs>
Can anyone help me with this? Any e.g or keywords what should I look up for this problem?
Assuming you are limited to XSLT 1.0, you can do:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:pl="http://www.w3.org/2001/XMLSchema/playlist"
xmlns:ns2="https://xml.netbeans.org/schema/genses"
exclude-result-prefixes="pl ns2">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="lookup-path" select="'Gerne.xml'" />
<xsl:key name="genre" match="ns2:gerne" use="pl:GerneCode" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GerneCode">
<xsl:variable name="code" select="." />
<!-- switch context to the other file -->
<xsl:for-each select="document($lookup-path)">
<GerneCode>
<xsl:value-of select="key('genre', $code)/pl:GerneName" />
</GerneCode>
</xsl:for-each>
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
This is assuming you are telling your XSLT processor to process the Song.xml file, and passing the path to the Gerne.xml file as a parameter.
Note that the Gerne.xml document you have posted is not well-formed XML (no </ns2:gernes> closing tag).
BTW, the correct term is "genre" - not "gerne" or "gense".

Using XSLT to recursively load relative XML files and apply transformation

I have a xml file whose structure looks like this:
<root>
<includes>
<includeFile name="../other/some_xml.xml"/>
</includes>
<itemlist>
<item id="1" >
<selections>
<selection name="one" />
</selections>
</item>
</itemlist>
The xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output method="xml" indent="yes" xalan:indent-amount="4" />
<xsl:template match="/">
<xsl:element name="ItemList">
<xsl:if test="root/item">
<xsl:call-template name="templ" />
</xsl:if>
</xsl:element>
</xsl:template>
<xsl:template name="templ">
<xsl:element name="ItemList">
<xsl:for-each select="root/itemlist/item">
<xsl:element name="Item">
<xsl:element name="ItemIdentifier">
<xsl:value-of select="#id" />
</xsl:element>
<xsl:element name="Condition">
<xsl:value-of select="selections/selection[1]/#name" />
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
I created one XSLT which i am using to filter out items. The problem is that for every file, i have to check if it contains the includefile tag, which is a relative path pointing to a similar xml, and if it does, i need to collect items from that file also, recursively. For now i transformed the xml using my xslt and then i have to parse the xml to look for includefile tag. This solution doesn't look elegant and i was wondering if all of it could be done via xslt.
The XSLT document function in XSLT 1.0 and in XSLT 2.0 additionally the doc function allow you to pull in further documents, processing is then simply possible with matching templates. So consider to move your XSLT coding style to write matching templates and apply-templates, then you can easily do
<xsl:template match="includes/includeFile">
<xsl:apply-templates select="document(#name)/*"/>
<xsl:template>
and then you simply need to make sure the <xsl:template match="root">...</xsl:template> creates the output you want.

Categories

Resources