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.
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 am trying to remove namespaces in an xml document and getting the following error:
ERROR: 'The prefix "car" for element "car:name" is not bound.'
ERROR: 'com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: The prefix "car" for element "car:name" is not bound.'
Here's my xml file:
<car:name>Toyota Corolla</car:name>
<car:year>2000</car:year>
Here's my removeNs.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="xml" indent="yes" />
<xsl:variable name="vLowercase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="vUppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:template match="*">
<xsl:element
name="{concat(translate(substring(local-name(), 1, 1),
$vUppercase, $vLowercase),
substring(local-name(), 2))}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name(.)}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
and my java method:
private static String stripNameSpaces(String inXml) {
String outputXml = "";
try {
StringWriter writer = new StringWriter();
TransformerFactory factory = TransformerFactory.newInstance();
Source xslt = new StreamSource(new File("./src/main/resources/removeNs.xslt"));
Transformer transformer = factory.newTransformer(xslt);
Source text = new StreamSource(new StringReader(inXml));
transformer.transform(text, new StreamResult(writer));
outputXml = writer.toString();
} catch (TransformerConfigurationException tcEx) {
tcEx.printStackTrace();
return tcEx.getMessage();
} catch (TransformerException tEx) {
tEx.printStackTrace();
return tEx.getMessage();
}
return outputXml;
}
My guess is that I have to add something to removeNs.xslt but have not been able to figure out what. If someone could help me with this, I'd really appreciate it
I am using javax.xml.transform API to do XSL transformation . The API only allows one XML document as an input to apply transformation as below .
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
StringWriter stringWriter = new StringWriter();
File xml = new File("C:\\abc");
File xsl = new File("C:\\def.xsl");
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(xml);
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
StreamSource style = new StreamSource(xsl);
Transformer transformer = transformerFactory.newTransformer(style);
DOMSource source = new DOMSource(document);
Also , can pass simple String params as below , without any issue as below :
transformer.setParameter("mode", "CREATE");
But , i want to pass an XML Document as a parameter to the XSL file . I tried below code as suggested on one of SO pages , as below :
DocumentBuilder builder = factory.newDocumentBuilder();
final Document documentFile = builder.parse(xml2);
Map<String, Document> docs = new HashMap<String, Document>();
docs.put("lookup", documentFile);
transformer.setURIResolver(new DocumentURIResolver(docs));
And i set , the tag in XML to receive value as below :
<xsl:variable name="lookup" select="('documentFile')/> .
But its not working for me . Can anyone help me out with the correct pay to pass multiple XML documents to any XSL file via javax.xml.transform API ?
Update
Still stuck with the issue ,can any one let me how can i pass XML object into a XSLT 2.0 stylesheet as a param . I have tried different approaches but no luck still . I need to know a way out via JAVA xsl transform API .
I think your issue is in the XSLT. Change
<xsl:variable name="lookup" select="('documentFile')/> .
to
<xsl:variable name="lookup" select="document('lookup')/>
this will cause the transformer to make the DOM of your document accessible in the variable lookup. The key lookup comes from docs.put("lookup", documentFile);
Dynamically Pass Multiple XML Sources to XSL Transformation via URIResolver.
Full Working Example:
Be there three XML files: repo.xml, books.xml and articles.xml. The repo.xml contains status information about books and articles. The files articles.xml and books.xml contain title information about each item. The goal is to print status information of all books and articles together with the title information. The entries in all files are connected via id keys.
Find complete example at github or copy/paste the listings below.
repo.xml
<repository>
<book>
<id>1</id>
<status>available</status>
</book>
<book>
<id>2</id>
<status>lost</status>
</book>
<article>
<id>1</id>
<status>in transit</status>
</article>
</repository>
books.xml
<books>
<book id="1">
<title>Book One</title>
</book>
<book id="2">
<title>Book Two</title>
</book>
<book id="3">
<title>Book Three</title>
</book>
</books>
articles.xml
<articles>
<article id="1">
<title>Article One</title>
</article>
<article id="2">
<title>Article Two</title>
</article>
<article id="3">
<title>Article Three</title>
</article>
</articles>
join.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<titleStatusJoin>
<xsl:for-each select="//book">
<xsl:variable name="myId" select="id" />
<book>
<status>
<xsl:value-of select="status" />
</status>
<title>
<xsl:for-each select="document('bookFile')//book">
<xsl:variable name="bookId" select="#id" />
<xsl:choose>
<xsl:when test="$myId = $bookId">
<xsl:value-of select="title" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</title>
</book>
</xsl:for-each>
<xsl:for-each select="//article">
<xsl:variable name="myId" select="id" />
<article>
<status>
<xsl:value-of select="status" />
</status>
<title>
<xsl:for-each select="document('articleFile')//article">
<xsl:variable name="bookId" select="#id" />
<xsl:choose>
<xsl:when test="$myId = $bookId">
<xsl:value-of select="title" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</title>
</article>
</xsl:for-each>
</titleStatusJoin>
</xsl:template>
</xsl:stylesheet>
Use this Java code...
#Test
public void useMultipleXmlSourcesInOneXsl3() {
InputStream xml = Thread.currentThread().getContextClassLoader().getResourceAsStream("stack54335576/repo.xml");
InputStream xsl = Thread.currentThread().getContextClassLoader().getResourceAsStream("stack54335576/join3.xsl");
InputStream booksXml = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("stack54335576/books.xml");
InputStream articlesXml = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("stack54335576/articles.xml");
Document booksDom = readXml(booksXml);
Document articlesDom = readXml(articlesXml);
Map<String, Document> parameters = new HashMap<>();
parameters.put("bookFile", booksDom);
parameters.put("articleFile", articlesDom);
xslt(xml, xsl, parameters);
}
public final void xslt(InputStream xml, InputStream xsl, Map<String, Document> parameters) {
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xsl));
transformer.setURIResolver((href, base) -> new DOMSource(parameters.get(href)));
transformer.transform(new StreamSource(xml), new StreamResult(System.out));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Document readXml(InputStream xmlin) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(xmlin);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
...to produce this output
<?xml version="1.0" encoding="UTF-8"?>
<titleStatusJoin>
<book>
<status>available</status>
<title>Book One</title>
</book>
<book>
<status>lost</status>
<title>Book Two</title>
</book>
<article>
<status>in transit</status>
<title>Article One</title>
</article>
</titleStatusJoin>
Did you already try this ?
org.w3c.dom.Document doc = ... // Your xml document
transformer.setParameter("demo", doc.getDocumentElement());
(Answer expanded to handle passing in a parsed W3C DOM document via a URIResolver)
This can be done in pure XSLT/XPath using the version of the Xalan XSLT processor that is supplied with the JRE.
As an example, say if the name of one of the input documents is passed in as a parameter to the Transformer:
File parentDir = new File("c:\\dir");
StringWriter stringWriter = new StringWriter();
File xml = new File(parentDir, "input.xml");
File xsl = new File(parentDir, "xslt-document-param.xslt");
Source xsltSource = new StreamSource(xsl);
Source xmlSource = new StreamSource(xml);
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer(xsltSource);
transformer.setParameter("doc-name", "basic.xml");
transformer.transform(xmlSource, new StreamResult(stringWriter));
System.out.println(stringWriter);
This parameter can then be passed into the document() function in XPath as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xalan"
version="1.0"
exclude-result-prefixes="xalan">
<xsl:output
method="xml"
indent="yes"
xalan:indent-amount="2"/>
<xsl:param name="doc-name"/>
<xsl:template match="/">
<xsl:variable name="doc-content" select="document($doc-name)"/>
<parent>
<xsl:for-each select="$doc-content/basic/*">
<child>
<xsl:value-of select="name(.)"/>
</child>
</xsl:for-each>
</parent>
</xsl:template>
</xsl:stylesheet>
This is able to read this basic.xml (from the parameter):
<basic>
<one/>
<two/>
<three/>
</basic>
And transform it to:
<parent>
<child>one</child>
<child>two</child>
<child>three</child>
</parent>
The parameter to the document() function is a URI. A relative path is resolved relative to the XSL file. Equally this could be a full URL, or resolved via a custom transformer.setURIResolver() as in the question.
(edit from here...)
To work with passing in a pre-parsed Document object to the XSLT, the URIResolver approach is able to handle passing this back to the document() function.
For example, with the lookup in the question:
File lookupXml = new File(parentDir, "basic.xml");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(lookupXml);
Map<String, Document> docs = new HashMap<>();
docs.put("lookup", document);
transformer.setURIResolver((href, base) -> new DOMSource(docs.get(href)));
This XSL is able to iterate through the same basic.xml as above...
<xsl:template match="/">
<xsl:variable name="doc-content" select="document('lookup')"/>
<parent>
<xsl:for-each select="$doc-content/basic/*">
<child>
<xsl:value-of select="name(.)"/>
</child>
</xsl:for-each>
</parent>
</xsl:template>
... and output the same result.
Not sure about your issue , if you give usecase and ask how to solve will be more helpful insted of asking how to fix your code as we are not having end to end visiblity of your code and xml.
Following could be possible solution :
1) We can convert xml to string
try {
StringReader _reader = new StringReader("<xml>vkhan</xml>");
StringWriter _writer = new StringWriter();
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(
new javax.xml.transform.stream.StreamSource("styler.xsl"));//ur xsl
transformer.transform(
new javax.xml.transform.stream.StreamSource(_reader),
new javax.xml.transform.stream.StreamResult(_writer));
String result = writer.toString();
} catch (Exception e) {
e.printStackTrace();
}
2) Modify below code as per your requirments pass as List of object of call in for loop.
public class Data {
public static final Document transformXmlDocument(Document sourceDocument, InputStream xsltFile) {
DOMSource xmlSource = new DOMSource(sourceDocument);
StreamSource xsltSource = new StreamSource(xsltFile);
Document transformedData = null;
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(xsltSource);
ByteArrayOutputStream output = new ByteArrayOutputStream();
StreamResult result = new StreamResult(output);
transformer.transform(xmlSource, result);
DocumentBuilder resultBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
transformedData = resultBuilder.parse(
new InputSource(
new StringReader(
new String(output.toByteArray())
)
)
);
} catch (Exception e) {
Log.e("XSLT Transformation", e.getMessage());
}
return transformedData;
}
}
https://gist.github.com/dazfuller/1559935/b84ee72db0e1de8ea25c54fbc744defbe4705ad9
Try to replace your <xsl:variable name="lookup" select="('documentFile')"/> instruction with <xsl:variable name="documentFile" select="document($lookup)"/> and pass your XML Document as a parameter with transformer.setParameter("lookup", "myfile.xml"); which means : load the document referenced by the lookup parameter into the documentFile variable.
See also Extract data from External XML file using XSL
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>
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