How can I join 2 XML in 1 XSL - java

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".

Related

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

Producing html xslt from xsl:fo

I'm tring to transform an xsl:fo into xslt (for HTML output). Then, I would apply xslt instead of xsl:fo obtaining the HTML output instead of a PDF.
How can do this?
I need API for XML Processing, or JAXP that transforms XML and XSL to another output. So, I tried to write the xslt template:
<xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo"
>
<xsl:template match="/xsl:template[#match='/root']/fo:root">
<xsl:apply-templates select="fo:page-sequence"/>
</xsl:template>
<xsl:template match="fo:page-sequence">
<xsl:for-each select="fo:flow[#flow-name='xsl-region-body']">
<xsl:call-template name="xsl-regional-body">
<xsl:with-param name="fontsize"><xsl:value-of select="#font-size"/></xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="xsl-regional-body">
<xsl:param name="fontsize" />
<body>
<xsl:if test="$fontsize"> <!-- costruisce <font size=""> -->
<font>
<xsl:attribute name="size">
<xsl:value-of select="$fontsize"/>
</xsl:attribute>
</font>
</xsl:if>
<xsl:for-each select="*/xsl:choose">
<xsl:call-template name="xsl-choose"/>
</xsl:for-each>
<xsl:apply-templates select="."/>
</body>
</xsl:template>
<xsl:template name="xsl-choose">
<xsl:value-of select="."/>
</xsl:template>
I obtain something like
<body><font size="10pt"/>
...
text words..
</body>
But it delete all xsl:choose xsl:when and other tags like
I need all these tags because i need to pass xml data in second pass using Jaxp and producing html..
I would obtain
<body><font size="10pt"/>
<xsl:choose>
<xsl:when test="ddx[#id='LET.....>
<xsl::value-of select="ddx[#id='Lx']/r/PE...>
</xsl:when>..
</xsl:choose>
text words..
</body>
How can get the XSL nodes like text node?
If you want to use XSLT to output XSLT elements (i.e. elements in the XSLT namespace) then you need to use a namespace alias as shown in http://www.w3.org/TR/xslt#literal-result-element:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias">
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<xsl:template match="/">
<axsl:stylesheet>
<xsl:apply-templates/>
</axsl:stylesheet>
</xsl:template>
<xsl:template match="block">
<axsl:template match="{.}">
<fo:block><axsl:apply-templates/></fo:block>
</axsl:template>
</xsl:template>
</xsl:stylesheet>
i put xsl: code between < ! CDATA [... ] ] >
anyway using another namespace

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.

Transforming XSL with XSL

A question about Martin's answer:
Martin Honnen's answer works great, but not with the root element. Let's say I have "cars" as a root element:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="foo">
<cars>
<car1 />
<car2 />
</cars>
</xsl:template>
</xsl:stylesheet>
And I want to obtain:
<xsl:template match="foo">
<cars>
<car1 />
<car2 />
<TANK />
</cars>
</xsl:template>
For this, I'd use:
<xsl:template match="cars" >
<xsl:copy>
<xsl:apply-templates/>
<TANK />
</xsl:copy>
</xsl:template>
Which outputs the exact input, without changing anything. I can try:
<xsl:template match="/" >
<xsl:copy>
<xsl:apply-templates/>
<TANK />
</xsl:copy>
</xsl:template>
But it will place the TANK node outside the stylesheet, like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="order">
<cars>
<car1/>
<car2/>
</cars>
</xsl:template>
</xsl:stylesheet><TANK/>
How to get the TANK element inside cars?
Original question:
I have a XSL that I use to transform an XML:
XML_format1 -> XSL1 -> XML_format2
I need to transform this first XSL file (using a second XSL) to obtain a third XSL file, which will output an XML with a third format. In short:
XSL1 -> XSL2 -> XSL3
XML_format1 -> XSL3 -> XML_format3
Using the following stylesheet, I am able to copy the first XSL's contents and also skip certain nodes:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//skipThisNode"/>
</xsl:stylesheet>
My problem: in addition to this, I also need to change some nodes' structure (add something), from this:
<car>
<color>green</color>
<fuel>petrol</fuel>
</car>
To this:
<car>
<color>green</color>
<fuel>petrol</fuel>
<topSpeed>99</topSpeed>
</car>
LE: I could create a template to match the specific nodes that I need to add children to, like so:
<xsl:template match="car">
<color>
<!-- existing value-of -->
</color>
<fuel>
<!-- existing value-of -->
</fuel>
<topSpeed>
<!-- * new value-of * -->
</topSpeed>
</xsl:template>
But this seems like going over the top. Is there a simpler way of achieving what I want?
I would rather use
<xsl:param name="newSpeed" select="99"/>
<xsl:template match="car">
<xsl:copy>
<xsl:apply-templates/>
<topSpeed>
<xsl:value-of select="$newSpeed"/>
</topSpeed>
</xsl:copy>
</xsl:template>
that keeps the processing chain up, allowing you to add templates to transform or delete child and descendants of car elements when needed.
[edit]
I am not sure I understand your latest requirement as the input seems to be a complete stylesheet but then as the wanted output you have only shown a single template. So assuming you have the input as
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="order">
<cars>
<car1 />
<car2 />
</cars>
</xsl:template>
</xsl:stylesheet>
and you want to both transform the xsl:template's match attribute as well as the literal result elements in the template body I would use
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xsl:template[#match = 'order']/#match">
<xsl:attribute name="{name()}">
<xsl:text>foo</xsl:text>
</xsl:attribute>
</xsl:template>
<xsl:template match="xsl:template[#match = 'order']/cars">
<xsl:copy>
<xsl:apply-templates/>
<TANK/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
that way I get (tested with Saxon 6.5.5) the result
<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="foo">
<cars>
<car1/>
<car2/>
<TANK/></cars>
</xsl:template>
</xsl:stylesheet>
which is hopefully what you want (lacking proper indentation perhaps).

XSLT for XML containing multiple namespaces

I'm working on an XSLT that is giving me a little headache, and was looking for some tips. I'm working on converting an XML where some of the tags have namespaces prefixes, and others do not. I am working to convert all of the tags to one common namespace prefix.
Example of XML:
<yes:Books>
<no:Book>
<Title>Yes</Title>
<maybe:Version>1</maybe:Version>
</no:Book>
</yes:Books>
What I'm trying to get:
<yes:Books>
<yes:Book>
<yes:Title>Yes</yes:Title>
<yes:Version>1</yes:Version>
</yes:Book>
</yes:Books>
The XML input is the aggregate of several webservices, that are returning various namespaces. I have no issue aggregating it together appropriately, it's creating one common prefix namespace that I am having an issue with.
Worst case, I could regex them away, but I'm sure that isn't recomended.
Thanks.
This transformation allows the wanted final prefix and its namespace to be specified as external/global parameters. It shows how to process in the same way attribute names:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pPrefix" select="'yes'"/>
<xsl:param name="pNamespace" select="'yes'"/>
<xsl:template match="*">
<xsl:element name="{$pPrefix}:{local-name()}" namespace="{$pNamespace}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{$pPrefix}:{local-name()}" namespace="{$pNamespace}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when applied on the following document (the provided one with one added attribute to make the problem more challenging):
<yes:Books xmlns:yes="yes">
<no:Book xmlns:no="no">
<Title no:Major="true">Yes</Title>
<maybe:Version xmlns:maybe="maybe">1</maybe:Version>
</no:Book>
</yes:Books>
produces the wanted, correct result:
<yes:Books xmlns:yes="yes">
<yes:Book>
<yes:Title yes:Major="true">Yes</yes:Title>
<yes:Version>1</yes:Version>
</yes:Book>
</yes:Books>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="c">
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="custom:{local-name()}" namespace-uri="c">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Categories

Resources