XML to JSON and back to XML in Java - java

I use XSLT to convert the XML to JSON. I use XSLT instead of Jackson/org.json as XSLT retains the namespace information.
For example, for the below SOAP XML request,
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<AccountDetailsRequest xmlns="http://com/blog/demo/webservices/accountservice">
<accountNumber>12345</accountNumber>
</AccountDetailsRequest>
</soap:Body>
</soap:Envelope>
converts it to the following JSON.
{"soap:Envelope":{"soap:Body":{"AccountDetailsRequest":{"accountNumber":"12345"}}}}
The namespace definition is lost. But, I plan to store the namespace definition in a map.
I use Jackson/org.json[both return similar results] to convert it back to XML and I get the following XML:
<soap:Envelope>
<soap:Body>
<AccountDetailsRequest>
<accountNumber>12345</accountNumber>
</AccountDetailsRequest>
</soap:Body>
</soap:Envelope>
The only part I am not able to figure out is the way to add the namespace definition assuming I can store that information in a map.
I considered adding a <root> </root> with all the namespaces in it, as W3C standard specifies it is a valid way to do so. But SOAP does not accept such XML.
Any way to get back the XML with proper namespace information?

When you say you're using XSLT to do the conversion, I guess that means you are doing it "by hand", rather than by using the XSLT 3.0 xml-to-json() function (which in fact wouldn't help you very much here).
But if your code has limitations, then it's hard to help you without seeing your code.
It's easy enough to find out all the namespaces in scope for an element by using the namespace axis, I'm not sure if you're trying that and getting it wrong, or if you're unaware of the feature. That's why we need to see your code.
It appears that the org.json converter accepts namespace declarations such as in:
String expectedStr =
"{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\","+
"\"something\":[1, 2, 3]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+
"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}";
so you need to modify your XML-to-JSON converter to generate such declarations. The code you've adopted does
<xsl:apply-templates select="#*" mode="attr" />
at line 39 to process attributes. In XSLT 2.0+ you could process namespaces the same way using select="namespace::*". IIRC correctly however, XSLT 1.0 can't match namespace nodes in a pattern, so if you're stuck on 1.0 you would need to use something like
<xsl:for-each select="namespace::*">
...
</xsl:for-each>

Related

Java signing XML File - prevent standard XML signature namespace inside signature

I'm signing an XML File where I'm using the Java XML Digital Signature API, available from Java 6 up to now.
Web-Source: http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html
The Signature looks like following:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">[...]</Signature>
Now I want to know, is there any way, to sign the XML File, to prevent the API to determine this xmlns="http://www.w3.org/2000/09/xmldsig#"inside my tag, so that I just have following:
<Signature>...</Signature>
I'm very thankful for any clues.
Thank you #Vadim for your answer. Lets give more details for my problem. I got a XML Structure like:
<?xml version="1.0" encoding="UTF-8" ?>
<tests xmlns="schema1">
<test>
</test>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
</Signature>
</tests>
How can I get this working? Because in a third party system I Need to check it against a Schema, where I define the structure of the signature by myself, so there should be like two xmlns inside my
Per XML standard you have to have namespace defined for <Signature> element, so it can be as you have it or outside on parent element with prefix. As
<rootElemnt xmlns:sig="http://....">
<sig:Signature>....
But, why it bother you? Without it <Signature> tag belongs to default namespace of parent element and not to proper Signature namespace.
UPDATED If you have two namespaces you have to have two xmlns declarations. One can be default second must have prefix. or both must have prefixes.
If your custom elements are in xmlns="schema1", I think you need to look either how to make <sig:Signature xmlns:sig="http://www.w3.org/2000/09/xmldsig#"> or
<sch1:tests xmlns:sch1="schema1">
<sch1:test>
</sch1:test>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
...
<sch1:customElement>...</sch1:customElement>
</Signature>
</sch1:tests>
It depends on how you build full XML. Sorry, I'do not know how to do that in Java XML Digital Signature API (never used it directly, just through WSDL policy), but all other tools have an ability to handle namespace prefixes
also it can look like:
<tests xmlns="schema1">
<test>
</test>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
...
<sch1:customElement xmlns:sch1="schema1">...</sch1:customElement>
</Signature>
</tests>
Perhaps it should look like that by defualt, but if not I guess if you marshal customElement into XML separately and then add it into Signature it must be like that.

Parse XML in which tag name is not fixed

It is easy to parse XML in which tags name are fixed. In XStream, we can simply use #XStreamAlias("tagname") annotation. But how to parse XML in which tag name is not fixed. Suppose I have following XML :
<result>
<result1>
<fixed1> ... </fixed1>
<fixed2> ... </fixed2>
</result1>
<result2>
<item>
<America>
<name> America </name>
<language> English </language>
</America>
</item>
<item>
<Spain>
<name> Spain </name>
<language> Spanish </language>
</Spain>
</item>
</result2>
</result>
Tag names America and Spain are not fixed and sometimes I may get other tag names like Germany, India, etc.
How to define pojo for tag result2 in such case? Is there a way to tell XStream to accept anything as alias name if tag name is not known before-hand?
if it is ok for you to get the tag from inside the tag itself (field 'name'), using Xpath, you can do:
//result2/*/name/text()
another option could be to use the whole element, like:
//result2/*
or also:
//result2/*/name()
Some technologies (specifically, data binding approaches) are optimized for handling XML whose structure is known at compile time. Others (like DOM and other DOM-like tree models - JDOM, XOM etc) are designed for handling XML whose structure is not known in advance. Use the tool for the job.
XSLT and XQuery try to blend both. In their schema-aware form, they can take advantage of static structure information when it is available. But more usually they are run in "untyped" mode, where there is no a-priori knowledge of element names or structure, and everything is handled as it comes. The XSLT rule-based processing paradigm is particularly well suited to "semi-structured" XML whose content is unpredictable or variable.

In JAXB or Xstream is it possible to Filter out certain Child Elements on Type/value during unmarshall

Hope everyone is well, quick question to see if anyone has any feedback.
I was experimenting with both JaxB and Xstream over last two days. I was basically using the XML libraries to marshal and unmarshal XML to / from Java objects. Now this was a very simple task which I got working very quickly. However, the XML I want to unmarshal into a list of Java objects is very long and contains many child elements that could be ignored and not put into the list of java objects.
For example the xml would look similar to:
<?xml version="1.0" encoding="UTF-8"?>
<Tables>
<Table1>
<TYPE>Test1</TYPE>
<DATE>2014-01-16</DATE>
<FLAG>True</FLAG>
</Table1>
<Table1>
<TYPE>Test2</TYPE>
<DATE>2014-01-15</DATE>
<FLAG>False</FLAG>
</Table1>
<Table1>
<TYPE>Test1</TYPE>
<DATE>2014-01-14</DATE>
<FLAG>True</FLAG>
</Table1>
</Tables>
So I would like the library to iterate through all the xml elements and unmarshal into a list of java objects which so far works, however as it iterates I would like to add additional functionality to check the Type and Flag element values, if TYPE value equals Test2 and or if Flag value equals False to ignore this child element all together and not include it in the finished list of Java objects. Does anyone know if this is possible with either JaxB or Xstream? Alternatively, can anyone suggest maybe a better approach to accomplish this which requires minimum code and manual parsing.
I have been looking at ValidationEventHandler and XmlAdapter in JaxB but I do not think these will allow me do what I want. I got close with the Xmldapter however the unmarshal has to return either null or an object for each xml child element it processes, it also changed the xml syntax to attribute form i.e TYPE = "Test1" etc which I did not see any way of altering.
Xstream allows you to implement a Converter which has a canConvert method, however this only works on Class type, and not child element type which I weant to check for each child element. Had a look at MapperWrapper wrapMapper method which can be overloaded in Xstream, but it only shows element attribute name, i.e FLAG and does not show value, also if it did show value I do not see anyway of telling the function to ignore child root element and all attributes for said child.
Anyway, that's my two cent. Any advice?
If you choose EclipseLink MOXy as your JAXB implementation (rather than the default implementation), you can use annotations on your Java classes for unmarshalling that employ XPath expressions. This could be used to filter out certain input. Here is the link: http://www.eclipse.org/eclipselink/moxy.php
Alternatively, and probably more simple, would be to use the XML transformation API with a stylesheet that has templates which filter out the unwanted content. Please check class javax.xml.bind.util.JAXBResult, which allows you to transform from one source (for example an InputStream or InputReader) directly to Java objects. Think of it as unmarshalling with a transformer in between.
EDIT:
I'll give you a hand with a basic XSLT and some code.
Here's the stylesheet that would do what you describe:
<?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" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="Table1[TYPE = 'Test1' or FLAG = 'True']">
<!-- Don't do anything, since we want to filter these Table1 elements out -->
</xsl:template>
</xsl:stylesheet>
And a code excerpt that can serve as a basis:
//Obtain a TransformerFactory
//Obtain a Source for your stylesheet, like a StreamSource
Transformer transformer = transformerFactory.newTransformer(source);
//Next, create an Unmarshaller from a JAXBContext
Unmarshaller unmarshaller = context.createUnmarshaller();
//Create a JAXBResult with the Unmarshaller
JAXBResult result = new JAXBResult(unmarshaller);
//Obtain a Source for your input XML, and transform
transformer.transform(inputSource, result);
//Get the JAXBElement from the result
final JAXBElement<?> jaxbEl = (JAXBElement<?>)result.getResult();
//And now your unmarshalled Java bean from the JAXBElement
Object bean = jaxbEl.getValue();

What is the best practice to send XML data embedded in a SOAP message?

I have a JAX-WS Web-Service which accepts some basic data and a String which is supposed to contains the content of a whole XML file.
In the first time I though I can just put this XML in my SOAP request as a CDATA section like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
...
<contentData>
<![CDATA[
<my>
<xml>
<here>
...
</here>
</xml>
</my>
]]>
</contentData>
...
</soapenv:Body>
</soapenv:Envelope>
But the issue is that my XML data contains as well some CDATA sections and it is not working like this as nested CDATA are not allowed (W3School reference).
What would be the best practice to send such data?
solution 1: escaping all special characters in order to have < and
> (among others)
solution 2: convert my XML in base64 and decode
it in my web-service
another solution welcome
I saw this question but serialising the Java object is not an option as the XML data are generated by another side.
I definitely prefer Solution 2, encoding and decoding Base64 formats.
I found this answer:
Use XmlDocument as param type in the Web-Service, rather than string
This is what the Web-Service I am communicating with is using.

ERROR: 'The first argument to the non-static Java function 'evaluate' is not a valid object reference.' when using TrasformFactory

I am trying to transform an xsl + xml to xml (for later on transforming it into a pdf using FOP library). The JDK I am using is 1.5, and there is no way I can use another (that is what the company I work in is using). I read that the xalan jar of java 1.5 is the one responsible for the error. The text that causes the error is:
"dyn:evaluate($xpath)"/>
in:
<xsl:variable name="paramName" select="#name"/>
<xsl:variable name="xpath"
select="concat('/doc/data/',$paramName)" />
<fo:inline>
<xsl:value-of select="dyn:evaluate($xpath)"/>
</fo:inline>
</xsl:template>
is there a way arround it without changing the jar? Is there a way to write it differently? or am I using the wrong syntax?
Thanks for your help
evaluate() is an EXSLT extension function. It is non-standard, but many XSLT processors, including xalan, support it.
Have you declared the dyn namespace prefix in your stylesheet, so that it correctly references the EXSLT dynamic namespace?
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
extension-element-prefixes="dyn">
...
</xsl:stylesheet>

Categories

Resources