I'm having fun with a weird xml response I get - the xml:
<params>
<param>
<value><array><data>
<value><string>UstId_1</string></value>
<value><string>xxx</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>ErrorCode</string></value>
<value><string>200</string></value>
</data></array></value>
</param>
</params>
Basically, the most inner <value><string> construct would normally be
<UstId_1>xxx</UstId_1>
and
<ErrorCode>200</ErrorCode>
respectively, so that the message of the xml boils down to
<params>
<UstId_1>xxx</UstId_1>
<ErrorCode>200</ErrorCode>
</params>
But this xml is different. It's returned by a tax authority, so there's no way to make them change that.
I currently have this pojo
#JacksonXmlRootElement(localName = "params")
public class Params {
#JacksonXmlProperty(localName = "param")
private List<Param> paramList = new ArrayList<>();
//getter setter ...
}
and Param:
public class Param {
#JacksonXmlProperty(localName = "value")
private Object value;
#JacksonXmlProperty(localName = "array")
private Object array;
#JacksonXmlProperty(localName = "data")
private Object data = new ArrayList<>();
//getter setter....
}
But that does only return the second entry from <value><string>, e.g.
xxx
and
200
Also it's a very strange construct
Params{paramList=[Param{value={array={data={value={string=xxx}}}}, array=null, data=null}
...
How would I correctly set up a pojo for that xml to ideally be able to do
res.getUstId1();
Maybe not what you were aiming for, but would an XSLT help you? You could transform the XML into something you can easily parse. Something 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 omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<params>
<xsl:for-each select="/params/param/value/array/data">
<xsl:element name="{value[1]/string}">
<xsl:value-of select="value[2]/string"/>
</xsl:element>
</xsl:for-each>
</params>
</xsl:template>
</xsl:stylesheet>
Fiddle: http://xsltransform.net/ejivdHU
Related
Can someone provide me the source code for replacing values dynamically for existing XSLT file using java object
XSLT File:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="CheckDomainCmd"/>
</xsl:template>
<xsl:template match="CheckDomainCmd">
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<check>
<domain:check xmlns:domain="http://www.nic.cz/xml/epp/domain-1.4" xsi:schemaLocation="http://www.nic.cz/xml/epp/domain-1.4 domain-1.4.xsd">
<domain:name><xsl:value-of select="DomainName"/>.<xsl:value-of select="TLD" /></domain:name>
</domain:check>
</check>
<clTRID>
<xsl:value-of select="RIMTransactionID"/>
</clTRID>
</command>
</epp>
</xsl:template>
</xsl:stylesheet>
Java Object:
public class checkDomain {
private String DomainName;
private String TLD;
private String RIMTransactionID;
// getters and setters
}
I need a source code in java/spring to put values to the XSLT select attribute dynamically.
For Example, in java object we have the following values, how to transform java object values to XSLT attributes:
public class XSLTConversion {
public static void main(String[] args) {
CheckDomain checkDomain = new CheckDomain():
checkDomain.setDomainName("test");
checkDomain.setTLD("com");
checkDomain.setRIMTransactionID("qwertyco123456");
replaceValuesToXSLTFile(checkDomain, "checkdomain.xslt");
}
public static void replaceValuesToXSLTFile(CheckDomain checkDomain, String fileName) {
}
}
After transformation, I need the file content like below
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="CheckDomainCmd"/>
</xsl:template>
<xsl:template match="CheckDomainCmd">
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<check>
<domain:check xmlns:domain="http://www.nic.cz/xml/epp/domain-1.4" xsi:schemaLocation="http://www.nic.cz/xml/epp/domain-1.4 domain-1.4.xsd">
<domain:name><xsl:value-of select="test"/>.<xsl:value-of select="com" /></domain:name>
</domain:check>
</check>
<clTRID>
<xsl:value-of select="qwertyco123456"/>
</clTRID>
</command>
</epp>
</xsl:template>
</xsl:stylesheet>
Your XSLT code needs to declare global parameters and reference them:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="DomainName"/>
<xsl:param name="TLD"/>
<xsl:param name="RIMTransactionID"/>
<xsl:template match="/">
<xsl:apply-templates select="CheckDomainCmd"/>
</xsl:template>
<xsl:template match="CheckDomainCmd">
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
<command>
<check>
<domain:check xmlns:domain="http://www.nic.cz/xml/epp/domain-1.4" xsi:schemaLocation="http://www.nic.cz/xml/epp/domain-1.4 domain-1.4.xsd">
<domain:name><xsl:value-of select="$DomainName"/>.<xsl:value-of select="$TLD" /></domain:name>
</domain:check>
</check>
<clTRID>
<xsl:value-of select="$RIMTransactionID"/>
</clTRID>
</command>
</epp>
</xsl:template>
</xsl:stylesheet>
then your Java code can create a Transformer from the XSLT and use e.g. transformer.setParameter("TLD", checkDomain.getTLD()) (see https://docs.oracle.com/javase/8/docs/api/javax/xml/transform/Transformer.html#setParameter-java.lang.String-java.lang.Object-) and so on for the other parameters before calling the transform method.
I have an xml file like the following:
<?xml version="1.0"?>
<Book>
<Title>Ulysses</Title>
<Author>James <b>Joyce</b></Author>
</Book>
I need to parse this using Java into a pojo like
title="Ulysses"
author="James <b>Joyce</b>"
In other words, I need the html or possible custom xml tags to remain as plain text rather than xml elements, when parsing.
I can't edit the XML at all but it would be ok for me to create a custom xslt file to transform the xml.
I've got the following Java code for using xslt to assist with the reading of the xml,
TransformerFactory factory = TransformerFactory.newInstance();
Source stylesheetSource = new StreamSource(new File(stylesheetPathname).getAbsoluteFile());
Transformer transformer = factory.newTransformer(stylesheetSource);
Source inputSource = new StreamSource(new File(inputPathname).getAbsoluteFile());
Result outputResult = new StreamResult(new File(outputPathname).getAbsoluteFile());
transformer.transform(inputSource, outputResult);
This does apply my xslt to the file which is written out but I can't come up with the correct xslt to do it. I had a look at Add CDATA to an xml file but this does not work for me.
Essentially, I believe I want the file to look like
<?xml version="1.0"?>
<Book>
<Title>Ulysses</Title>
<Author><![CDATA[James <b>Joyce</b>]]></Author>
</Book>
Then I can extract
"James <b>Joyce</b>". I tried the approach suggested here: Add CDATA to an xml file
But it did not work for me.
I used the following xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
<xsl:template match="Author">
<xsl:copy>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:copy-of select="*"/>
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:copy>
</xsl:template>
and this produced:
<?xml version="1.0" encoding="UTF-8"?>
Ulysses
<Author><![CDATA[
<b>Joyce</b>]]></Author>
Can you please help with this? I want the original document to be written out in it's entirety but with the CDATA surrounding everything within the author element.
Thanks
Isn't using a simple html/xml parser like Jsoup a better way of solving this?
Using Jsoup you can try something like this:
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;
public class Example {
public static void main(String[] args) {
String xml = "<?xml version=\"1.0\"?>\n"
+ "<Book>\n"
+ " <Title>Ulysses</Title>\n"
+ " <Author>James <b>Joyce</b></Author>\n"
+ "</Book>";
Document doc = Jsoup.parse(xml, "", Parser.xmlParser());
doc.outputSettings().prettyPrint(false);
Elements books = doc.select("Book");
for(Element e: books){
Book b = new Book(e.select("Title").html(),e.select("Author").html());
System.out.println(b.title);
System.out.println(b.author);
}
}
public static class Book{
String title;
String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
}
}
With XSLT 3.0 as supported by Saxon 9.8 HE (available on Maven and Sourceforge) you can use XSLT as follows:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:output cdata-section-elements="Author"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="Author">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:value-of select="serialize(node())"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
As for your attempt, you basically need to "implement" the identity transformation template concisely written in XSLT 3.0 as <xsl:mode on-no-match="shallow-copy"/> as a template
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
in XSLT 1.0 so that those nodes not handled by more specialized template (like the one for Author elements) are recursively copied through.
Then, with the copy-of selecting all child nodes node() and not only the element nodes * you get
<xsl:template match="Author">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:copy-of select="node()"/>
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:copy>
</xsl:template>
What I want to do?
I'm working on a Apache Cocoon Project and want to find solution to return paramaters in HTML pages.
I need to get the parameter, which has ArrayList type, and use it in HTML page in order to fill a table. How can I do this? Is it correct to set a request parameter? If yes, then how to use it inside HTML code? If no, then how to return the parameter correctly?
ActionClass.java
public class ActionClass implements Action, ThreadSafe{
public Map act(Redirector rdrctr, org.apache.cocoon.environment.SourceResolver sr, Map map, String string, Parameters params) throws Exception {
// READ REQUEST
Request request = ObjectModelHelper.getRequest(map);
// DO SOMETHING XQUERY VIA BASEX, SPARQL RDFSTORE WHATEVER
ArrayList<ResultBean> results = xquery();
Map sitemapParams = new HashMap();
// SET REQUEST PARAMETER
request.setAttribute("results",results);
return sitemapParams;
}
}
ResultBean.java
package com.kiddo.grlegislation;
public class ResultBean {
private String id;
private String title;
private String type;
public void setId(String i){
this.id = i;
};
public void setTitle(String t){
this.title = t;
};
public String getId(){
return this.id;
};
public String getTitle(){
return this.title;
};
}
First of all, are you sure that you need an Action? Actions are meant to act somehow (update something in the database, invoke a web service, etc). If you just need to generate content, a Generator class could be a better fit for you...
Anyway... How could you return something from an Action into HTML? Lets see it with an example:
Action class: because it extends Action, it must return a Map. Just add there whatever data you need to pass to your HTML:
package com.stackoverflow;
public class ActionClass extends Action {
public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters params) {
Map<String, String> sitemapParams = new HashMap<String, String>();
sitemapParams.put("myVariable", "hello world!");
return sitemapParams;
}
}
sitemap.xmap: in your sitemap file, you can access any data returned by the Action, by placing it's key between brackets. Then you can pass it to your HTML generator:
<map:components>
<map:actions>
<map:action name="myAction" src="com.stackoverflow.ActionClass" />
</map:actions>
</map:components>
...
<map:match ...>
<map:generate ... />
<map:act type="myAction">
<map:transform src="myTransformation.xsl">
<map:parameter name="something" value="{myVariable}"/>
</map:transform>
</map:act>
<map:serialize .../>
</map:match>
myTransformation.xsl: your XSLT file should read the data and embed it into your HTML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="something" select="'default value if you wish to specify one'"/>
<xsl:template match="xxx">
<html><body>...
<xsl:value-of select="$something" />
...</body></html>
</xsl:template>
</xsl:stylesheet>
You can get more information about Actions, Generators and the sitemap in this page. It's from Apache Cocoon 2.1 documentation, but it also applies to 2.2.
Alternative approach, with a Generator:
Generator class: this file builds a XML document, which is then passed into the pipeline. You could have something like this:
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
...
public class GeneratorClass extends AbstractGenerator {
private String foo;
#Override
public void setup(SourceResolver resolver, Map objectModel, String src, Parameters params) throws ProcessingException, SAXException, IOException {
super.setup(resolver, objectModel, src, params);
// you can read input parameters in here:
foo = params.getParameter("someParameter");
}
public void generate() throws IOException, SAXException, ProcessingException {
ArrayList<ResultBean> beans = xQuery(foo);
// Let's build the XML document. I'll do it by manually appending text strings,
// but there is no need, we could just use Xstream or any similar library
StringBuilder xml = new StringBuilder();
xml.append("<results>");
// Iterate through the array list...
for (ResultBean b : beans) {
xml.append("<result>");
xml.append("<id>").append(b.getId()).append("</id>");
xml.append("<title>").append(b.getTitle()).append("</title>");
xml.append("</result>");
}
// ... and we end the XML string
xml.append("</results>");
// Return the XML to Cocoon's pipeline
XMLReader xmlreader = XMLReaderFactory.createXMLReader();
xmlreader.setContentHandler(super.xmlConsumer);
InputSource source = new InputSource(new StringReader(xml.toString()));
xmlreader.parse(source);
try {
this.finalize();
} catch (Throwable e) {
}
}
}
Sitemap.xmap: you just need to call your generator, and then apply your XSLT to the generated XML:
<map:components>
<map:generators>
<map:generator type="myGenerator" src="com.stackoverflow.GeneratorClass" />
</map:generators>
/<map:components>
<map:generate type="myGenerator">
<!-- if you need to pass input data to the generator... -->
<map:parameter name="someParameter" select="{request-param:something}" />
</map:generate>
<map:transform src="myTransformation.xsl" />
<map:serialize type="html"/>
myTransformation.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head></head>
<body>
<table>
<xsl:for-each select="results/result">
<tr>
<td><xsl:value-of select="id/text()"/></td>
<td><xsl:value-of select="title/text()"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
You can get more info about Cocoon generators here. Once again, it's an official tutorial for Cocoon 2.1, but it's also valid for Cocoon 2.2.
I'm trying to do something like this and it seems to work:
<map:pipeline id="pd-version">
<map:match pattern="pd/*/*">
<map:aggregate element="foo">
<map:part src="cocoon:/version-{1}-{2}.xml"/>
<map:part src="http://localhost:8888/GRLegislation/pd/{1}/{2}/data.xml"/>
</map:aggregate>
<map:transform src="legislation_updated.xslt" type="xslt-saxon"/>
<map:transform src="legislation.xslt" type="xslt-saxon">
</map:transform>
<map:serialize type="xhtml"/>
</map:match>
</map:pipeline>
<map:pipeline>
<map:match pattern="version-*-*">
<map:generate type="versiongen">
<map:parameter name="type" value="pd"/>
<map:parameter name="year" value="{1}"/>
<map:parameter name="id" value="{2}"/>
</map:generate>
<map:serialize type="xml"/>
</map:match>
</map:pipeline>
Parameters are not loaded correctly from <map:part> to <map:match>. Also I have some XSLT issues, because now we have a different root of XML.
I have an XML file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
</catalog>
And this XSL file:
<?xml version="1.0" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="/catalog/cd/artist"/>
<xsl:variable name = "artist" select = "/catalog/cd/artist()"/>
<xsl:variable name="year" select="/catalog/cd/year()"/>
<xsl:Object-bean name="{$artist}" id="{$year}">
</xsl:Object-bean>
</xsl:template>
</xsl:stylesheet>
Now I want to transform the result into a Java class.
Java:
#XmlRootElement(name = "Object-bean")
#XmlAccessorType(XmlAccessType.NONE)
public class ObjectBean {
#XmlAttribute(name = "name")
private String name;
#XmlAttribute
private String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
but when i run it it show me this error:
Error at xsl:Object-bean on line 7 column 49 of test.xsl:
XTSE0010: Unknown XSLT element: Object-bean
Exception in thread "main" javax.xml.transform.TransformerConfigurationException: Failed to compile stylesheet. 1 error detected.
at net.sf.saxon.PreparedStylesheet.prepare(PreparedStylesheet.java:176)
at net.sf.saxon.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:139)
at net.sf.saxon.TransformerFactoryImpl.newTransformer(TransformerFactoryImpl.java:91)
at XslExecutor.main(XslExecutor.java:28)
The XML holds the original data (Document A). The XSLT is a transformation template that translates the XML data (Document A) into other XML document (Document B).And finally you are trying to marshall the output of the XSLT template (Document B) into a POJO annotated with JAXB. JAXB annotations work similar to the XSLT template. They provide a binding mechanism between XML and a POJO.
XSLT JAXB
(XML Document A) ---------------------> (XML Document B) -------------------->POJO
That explained, just to set a common understanding, the output you are showing says the XSLT transformation is failing. In fact the XSL you provide is completely wrong. Start with something like this, that works with the XML you provided:
<?xml version="1.0" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:element name="Object-bean">
<xsl:attribute name="artist">
<xsl:value-of select="/catalog/cd/artist"/>
</xsl:attribute>
<xsl:attribute name="year">
<xsl:value-of select="/catalog/cd/year"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The reason of the error is your incorrect xslt template. What do you want to achieve by applying xslt transformation? If by doing so you want to build POJO it is not a good idea..
At first you have to transform your initial xml file with xslt template and after this you have to unmarshal xml to your POJO using JAXB.
I have a xml structure "Filter" that get unmarshalled into in a java class called "Filter".
The XML state looks roughly like:
<filter>
<propertyType>
<propertyName>prop1</propertyName>
<propertyValue>val1</propertyValue>
</propertyType>
<propertyType>
<propertyName>prop2</propertyName>
<propertyValue>val2</propertyValue>
</propertyType>
</filter>
Ordinarily, it works great.
However, there are certain situations where one of these property values itself contains xml structure (see second propertyValue below):
<filter>
<propertyType>
<propertyName>prop1</propertyName>
<propertyValue>val1</propertyValue>
</propertyType>
<propertyType>
<propertyName>prop2</propertyName>
<propertyValue><nodeA><nodeB>valB</nodeB></nodeA></propertyValue>
</propertyType>
</filter>
The problem here is that after unmarshalling this structure, the propertyValue is null.
I would like to simply be able to have the unmarshalling ignore this xml-looking code and treat it as a simple string value.
Does anyone know how I can accomplish this? Thanks for any reply!
How about the annotation of using "#XmlAnyElement"?
You can get the instance of org.w3c.dom.Element.
The text data should be able to be obtained by operating this instance.
class PropertyType {
private String propertyName;
// private String propertyValue; // comment out
#XmlAnyElement(lax=true)
private List<org.w3c.dom.Element> propertyValue; // Adding this
}
exsample of to get text data.
// It is assumed that the child node is one.
org.w3c.dom.Node nd = propertyValue.get(0).getFirstChild();
while(true) {
if (nd.hasChildNodes()) {
nd = nd.getFirstChild();
} else {
System.out.println(nd.getNodeValue()); // this is text data
break;
}
}
For this use case I would create an XSLT that will convert the XML document. Then using the javax.xml.transform.* APIs, transform the XML to a JAXBResult to unmarshal the object:
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.util.JAXBResult;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
File xsltFile = new File("transform.xsl");
StreamSource xsltSource = new StreamSource(xsltFile);
Transformer transformer = tf.newTransformer(xsltSource);
File xml = new File("input.xml");
StreamSource xmlSource = new StreamSource(xml);
JAXBContext jc = JAXBContext.newInstance(Filter.class);
JAXBResult jaxbResult = new JAXBResult(jc);
transformer.transform(xmlSource, jaxbResult);
Filter filter = (Filter) jaxbResult.getResult();
}
}
transform.xsl
<?xml version="1.0" encoding="UTF-8"?>
<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="propertyValue"> <xsl:value-of select="descendents"/>
<xsl:element name="propertyValue">
<xsl:value-of select="node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
AFAIK the JAXB work on xml schema for unmarshalling XML into Java object. So if schema defines element as simple element, it can only contain text. If you need to store XML as simple text. You might need to escape it using CDATA construct. Try enclosing the same as shown below, after unmarshling you will get the XML as it is.
<filter>
<propertyType>
<propertyName>prop1</propertyName>
<propertyValue>val1</propertyValue>
</propertyType>
<propertyType>
<propertyName>prop2</propertyName>
<propertyValue><![CDATA[<nodeA><nodeB>valB</nodeB></nodeA>]]></propertyValue>
</propertyType>
</filter>