Embedding XSL Stylesheet into XML - java

I have the following XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="http://www.fakedomain.com/sally.xsl"?>
And the following content in sally.xsl:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="documentcollection/document">
<p>
<xsl:for-each select="rss/channel/item">
<xsl:value-of select="title"/><br />
<xsl:value-of select="description"/><br />
<xsl:value-of select="link"/><br />
</xsl:for-each>
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
However, the browser displays the XML as though the XSL line is not present. Do you know why the browser is ignoring the XSL stylesheet? Is the style sheet wrong?
Thanks

I have the following XML:
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml-stylesheet type="text/xsl" href="http://www.fakedomain.com/sally.xsl"?>
This isn't a well-formed XML document (no top element present), so it isn't much of a surprize the browser doesn't treat it as such.
Solution:
Update your "XML" to a really well-formed XML document, something like:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="file:///c:/temp/delete/xxx.xsl"?>
<t/>
With this stylesheet in c:\temp\delete\xxx.xsl:
<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:template match="/">
XXX
</xsl:template>
</xsl:stylesheet>
when the XML file is opened with IE, the browser displays the result of the transformation:
XXX

Looks like your not closing off one of your for-each tags?

the xsl:for-each loop of select="rss/channel/item" is not closed.

It could be same origin policy security restrictions. If your XML and XSLT are not hosted in the same location, then the browser may be refusing to fetch the XSLT and apply it to your XML file.

Related

How to retrieve duplicate nodes from XML using xpath or java script

Below is my input xml.
<?xml version="1.0" encoding="UTF-8"?>
<Hierarchy>
<Records>
<Org_Unit_Name>ABC</Org_Unit_Name>
<Parent_Org_Unit>123</Parent_Org_Unit>
</Records>
<Records>
<Org_Unit_Name>ABC</Org_Unit_Name>
<Parent_Org_Unit>DEF</Parent_Org_Unit>
</Records>
<Records>
<Org_Unit_Name>456</Org_Unit_Name>
<Parent_Org_Unit>879</Parent_Org_Unit>
</Records>
</Hierarchy>
I would like to extract only duplicate values. so the output should be as below
<?xml version="1.0" encoding="UTF-8"?>
<Hierarchy>
<Records>
<Org_Unit_Name>ABC</Org_Unit_Name>
<Parent_Org_Unit>123</Parent_Org_Unit>
</Records>
<Records>
<Org_Unit_Name>ABC</Org_Unit_Name>
<Parent_Org_Unit>DEF</Parent_Org_Unit>
</Records>
I tried preceding axes in xpath/xslt, but of no use and unique(false) in java script but I am unable to retrieve the expected output. Please guide me how to proceed forward.
Regards,
Amuktha
Assuming that "duplicate" means a Records element with the same Org_Unit_Name value, you could use a variation of Muenchian grouping:
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:key name="Records-by-Org_Unit_Name" match="Records" use="Org_Unit_Name" />
<xsl:template match="/Hierarchy">
<xsl:copy>
<xsl:copy-of select="Records[count(key('Records-by-Org_Unit_Name', Org_Unit_Name)) > 1]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

XSLT to pick specific nodes, and parameterizing it from Java

I have an XML structure like this,
<?xml version="1.0" encoding="UTF-8"?>
<Package>
<PackageHeader>yadda yadda </PackageHeader>
<PackageBody>
<Element1>foo</Element1>
<Element2>bar</Element2>
<ElementN>xyz</ElementN>
</PackageBody>
I have a requirement where I need to eliminate either Element1, Element2, or ElementN, so I wrote this XSLT,
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()[not(self::Element1)][not(self::Element2)]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I am running this via a simple Java XSL Transformation program. The transformed XML has only elevrything from the orignal XML minus Element1 & Element2. I tried many ways to pass parameters from the Java program to parameterize which nodes should be eliminated, but no luck so far. Any help would be much appreciated.
Sounds like a task for XSLT 3 with static parameters and shadow attributes, best used with the Saxon s9api (http://saxonica.com/html/documentation9.9/javadoc/index.html) if that is the processor used:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="element-to-be-removed" static="yes" as="xs:string" select="'Element2'"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template _match="{$element-to-be-removed}"/>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/gVhEaiE

Websphere - Transformer.setParameter not working

I have an XSLT which i use to transform an XML using Java. The code is working fine when i run it in eclipse and use Apache Tomcat. But when i deploy the ear file to WebSphere, the field is showing as blank. Does anyone have ideas?
The java variables 'reportId' and 'proposalId' are set as i used System.out.println() and could see the value is set.
Java Code
// Use the factory to create a template containing the xsl file
Templates template = factory.newTemplates(new StreamSource(is));
// Use the template to create a transformer
Transformer xformer = template.newTransformer();
xformer.setParameter("reportId", reportId);
xformer.setParameter("proposalId", proposalId);
<xsl:param name="proposalId"/>
<xsl:param name="reportId"/>
I then use the following in the XSLT to read the parameter:
<td align="left"><b>Proposal Ref: </b> <xsl:value-of select="$proposalId"/>
</td>
<td align="left"><b>Report Id: </b> <xsl:value-of select="$reportId"/>
</td>
I found that i had the param inside the template tag. The transformer can not set the value of a template level variable. It can only set it on a global level variable. So my code was 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="html"/>
<xsl:template match="/">
<xsl:param name="proposalId"/>
<xsl:param name="reportId"/>
</xsl:template>
</xsl:stylesheet>
but it should have been:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:param name="proposalId"/>
<xsl:param name="reportId"/>
<xsl:template match="/">
</xsl:template>
</xsl:stylesheet>

Splitting an xml based on the contents of xml either using java or xslt

I have a requirement,consider the below xml data
Input1.xml
<Envelope>
<Notification>
<Data>
<Input>ABCDEFGHIJKLMN</Input>
<Output>RESPONSEDATA</Output>
</Data>
<Data>
<Input>OPQRSTUVWXYZ</Input>
<Output>NEXTDATA</Output>
</Data>
<Data>
<Input>ALPHABETS</Input>
<Output>SOMEDATA</Output>
</Data>
</Notification>
</Envelope>
Now I want 3 output xmls with the response as shown below the file name to have first 6 characters ofABCDEFGHIJKLMN as output file name to have as shown below
(FILE1)->ABCDEF.XML
<Output>RESPONSEDATA</Output>
(FILE2)->OPQRST.XML
<Output>NEXTDATA</Output>
(FILE3)->ALPHAB.XML
<Output>SOMEDATA</Output>
Which XSLT 1.0 processor do you use? Xalan Java supports
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:redirect="http://xml.apache.org/xalan/redirect"
extension-element-prefixes="redirect"
exclude-result-prefixes="redirect">
<xsl:template match="/Envelope/Notification/Data[not(Input/*)]">
<redirect:write select="concat(substring(Input, 1, 6), '.xml')">
<xsl:copy-of select="Output"/>
</redirect:write>
</xsl:template>
<xsl:template match="/Envelope/Notification/Data[Input/*]">
<redirect:write select="concat(local-name(Input/*), '.xml')">
<xsl:copy-of select="Output"/>
</redirect:write>
</xsl:template>
</xsl:stylesheet>
Use the solution described in Your Previous Question you can then create 3 xslt files as follow, and apply the same xml input one for each xslt/output. Explain:
<xsl:copy-of select="/Envelope/Notification/Data[child::Output/text()='RESPONSEDATA']"/>
is saying, copy all "/Envelope/Notification/Data" and it content, but only for the child Output with a text value of 'RESPONSEDATA'.
ExtractResponseData.xslt
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes" />
<xsl:template match="/">
<xsl:copy-of select="/Envelope/Notification/Data[child::Output/text()='RESPONSEDATA']"/>
</xsl:template>
</xsl:stylesheet>
ExtractNextData.xslt
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes" />
<xsl:template match="/">
<xsl:copy-of select="/Envelope/Notification/Data[child::Output/text()='NEXTDATA']"/>
</xsl:template>
</xsl:stylesheet>
ExtractSomeData.xslt
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes" />
<xsl:template match="/">
<xsl:copy-of select="/Envelope/Notification/Data[child::Output/text()='SOMEDATA']"/>
</xsl:template>
</xsl:stylesheet>

Mapping two sources to one output

I want to performs XSLT on two sources.
Sourch_1.xml:
<Root>
<record>
<PolicyNumber>1</PolicyNumber>
<FirdsName>aa</FirdsName>
<LastName>aa</LastName>
</record>
<record>
<PolicyNumber>2</PolicyNumber>
<FirdsName>bb</FirdsName>
<LastName>bb</LastName>
</record>
Sourch_2.xml:
<Root>
<record>
<policy>
<PolicyNumber>1</PolicyNumber>
<city>aaCity</city>
<street>aaStreet</street>
</policy>
<policy>
<PolicyNumber>2</PolicyNumber>
<city>bbCity</city>
<street>bbStreet</street>
</policy>
</record>
I want the output to create tags which combine data from two sources based on PolicyNumber.
I want my output to be:
output.xml:
<Root>
<record_data>
<PolicyNumber>1</PolicyNumber>
<FirdsName>aa</FirdsName>
<LastName>aa</LastName>
<city>aaCity</city>
<street>aaStreet</street>
</record_data>
<record_data>
<PolicyNumber>2</PolicyNumber>
<FirdsName>bb</FirdsName>
<LastName>bb</LastName>
<city>bbCity</city>
<street>bbStreet</street>
</record_data>
How can i accomplish that using XSLT?
To process more than one XML input file, use the document() function. Make sure that additional XML files are in the folder where you put the XSLT stylesheet, too.
The line that deserves your attention is the following:
<xsl:for-each select="document('double2.xml')/root/record/policy[./PolicyNumber=current()/PolicyNumber]">
To begin with, document('double2.xml') opens the second XML file (I have dubbed it "double2.xml"). For the policy elements in this second XML file it checks whether their PolicyNumber is equal to the PolicyNumber of the record element from the first XML file that is being processed
I have slightly modified your input to make it well-formed (lowercased the root element and added its closing tag). Note that there is also a typo in it and you probably meant to write "FirstName" instead of "FirdsName".
Stylesheet
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="record">
<record_data>
<xsl:copy-of select="*"/>
<xsl:for-each select="document('double2.xml')/root/record/policy[./PolicyNumber=current()/PolicyNumber]">
<xsl:copy-of select="city|street"/>
</xsl:for-each>
</record_data>
</xsl:template>
</xsl:stylesheet>
Output
<?xml version="1.0" encoding="UTF-8"?>
<root>
<record_data>
<PolicyNumber>1</PolicyNumber>
<FirdsName>aa</FirdsName>
<LastName>aa</LastName>
<city>aaCity</city>
<street>aaStreet</street>
</record_data>
<record_data>
<PolicyNumber>2</PolicyNumber>
<FirdsName>bb</FirdsName>
<LastName>bb</LastName>
<city>bbCity</city>
<street>bbStreet</street>
</record_data>
</root>
Something like below will work for you.
NOTE : I have not ran this code. where I check not(policy) you might do some change in xpath like not(./policy)
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="Root/record">
<xsl:choose>
<xsl:when test="not(policy)">
<record_data>
<PolicyNumber><xsl:value-of select="PolicyNumber"/></PolicyNumber>
<FirdsName><xsl:value-of select="FirdsName"/></FirdsName>
<LastName><xsl:value-of select="LastName"/></LastName>
<city><xsl:value-of select="city"/></city>
<street><xsl:value-of select="street"/></street>
</record_data>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
<record_data>
<PolicyNumber><xsl:value-of select="policy/PolicyNumber"/></PolicyNumber>
<FirdsName><xsl:value-of select="policy/FirdsName"/></FirdsName>
<LastName><xsl:value-of select="policy/LastName"/></LastName>
<city><xsl:value-of select="policy/city"/></city>
<street><xsl:value-of select="policy/street"/></street>
</record_data>
</xsl:choose>
</xsl:for-each>

Categories