Getting MOXy #XmlPath to Work with Namespace - java

I'm writing a script to parse a KML file using JAXB and MOXy, but I'm having difficulty getting #XmlPath to work with a provided namespace.
If my KML looks like this:-
<kml>
<Document>
<name>Test</name>
</Document>
</kml>
... and my bean looks like this:-
#XmlRootElement(name = "kml")
public class Kml {
#XmlPath("Document/name/text()")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
... then, kml.getName() returns Test, which works like it should.
However, if my KML contains a namespace like this:-
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Test</name>
</Document>
</kml>
... and my bean looks like this:-
#XmlRootElement(name = "kml", namespace = "http://www.opengis.net/kml/2.2")
public class Kml {
#XmlPath("Document/name/text()")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
... then, kml.getName() returns null.
I do have jaxb.properties at the right package level and I'm using the following MOXy's dependency:-
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.3.2</version>
</dependency>
What exactly am I missing here? Thanks.

Below is an example demonstrating how to configure the namespace information.
package-info
You can use the #XmlSchema annotation to specify the namespace information and qualification. In the example below we will specify the namespace, and that by default all elements should be namespace qualified.
#XmlSchema(
namespace="http://www.opengis.net/kml/2.2",
elementFormDefault=XmlNsForm.QUALIFIED)
#XmlAccessorType(XmlAccessType.FIELD)
package forum9931520;
import javax.xml.bind.annotation.*;
Kml
We do not need to specify any namespace information in the Kml class. This information comes from the settings in package-info:
package forum9931520;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name = "kml")
public class Kml {
#XmlPath("Document/name/text()")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Demo
package forum9931520;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Kml.class);
File xml = new File("src/forum9931520/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Kml kml = (Kml) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(kml, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Test</name>
</Document>
</kml>
For More Information
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

Related

Object to xml tag and format soap envelope in Spring Boot

I am new in Spring Boot application i face an issue with xml format to soap envelope like below detail:
I need to convert object from java class to xml and format xml tag to soap envelop like below:
Bookstore.java
package com.example.wsdltojavaclass.xmlrequest;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlType;
import javax.xml.namespace.QName;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "", namespace = "http://schemas.xmlsoap.org/soap/envelope/")
public class Bookstore {
#XmlElementWrapper(name = "bookList")
#XmlElement(name = "book")
private List < Book > bookList;
private String name;
private String location;
// public void setBookList(List < Book > bookList) {
// this.bookList = bookList;
// }
//
// public List < Book > getBooksList() {
// return bookList;
// }
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
My Controller:
#GetMapping("/xml")
public void newroute() throws JAXBException, FileNotFoundException, JAXBException {
List<Book> bookList = new ArrayList<Book>();
Bookstore bookstore = new Bookstore();
bookstore.setName("Amazon Bookstore");
bookstore.setLocation("Newyorkt");
convertObjectToXML(bookstore);
}
private static void convertObjectToXML(Bookstore bookstore) throws JAXBException, FileNotFoundException {
JAXBContext context = JAXBContext.newInstance(Bookstore.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(bookstore, System.out);
m.marshal(bookstore, new File(BOOKSTORE_XML));
}
And here is my result:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2: xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/">
<name>Amazon Bookstore</name>
<location>Newyorkt</location>
</ns2:>
My expected result i need to change remove <?xml version="1.0" encoding="UTF-8" standalone="yes"?> and change format to
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:web="http://www.dataaccess.com/webservicesserver/">
<soap:Header/>
<soap:Body>
<web:name>Amazon Bookstore</web:name>
<web:location>Newyorkt</web:location>
</soap:Body>
</soap:Envelope>
So how to change from ns2 to soap envelope?

Create XML string in java with custom namespace

I want to generate xml string in java programmatically whose name space is custom as shown below
and all data must come dynamically in xml.How can I achieve something like this?
<faxml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="test.xsd">
<person>
<name>ABC</name>
</person>
</faxml>
I have gone through examples like this https://howtodoinjava.com/jaxb/write-object-to-xml/ but here when xml generated its starting line is
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
but I want start and end tag <faxml> and namespaces as I mentioned in my sample code as output
Here is one approach:
First, here is my class representing the required XML data:
package org.ajames.jaxb.persons;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "faxml")
public class Faxml {
private Person person;
public static class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
I chose to nest the Person class inside the root class - just for this test. There are other ways to arrange these classes, of course, so they are not nested.
Then I define the package-info for org.ajames.jaxb.persons as follows:
#XmlSchema(
namespace = "",
elementFormDefault = XmlNsForm.UNSET,
xmlns = {
#XmlNs(prefix = "", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance")
})
package org.ajames.jaxb.persons;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
To process the data from a Java object to XML, I use the following test data:
Faxml.Person person = new Faxml.Person();
person.setName("ABC");
Faxml faxml = new Faxml();
faxml.setPerson(person);
The JAXB context and marshaller are as follows, assuming we are writing the XML to a Java String, for this test:
JAXBContext jaxbContext = JAXBContext.newInstance(Faxml.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "test.xsd");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter stringWriter = new StringWriter();
marshaller.marshal(faxml, stringWriter);
String xml = stringWriter.toString();
System.out.println(xml);
The resulting XML is:
<faxml xsi:noNamespaceSchemaLocation="test.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<person>
<name>ABC</name>
</person>
</faxml>
String name= "name"
String createXml="<faxml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"//
xsi:noNamespaceSchemaLocation="test.xsd">"//
+"<person>"//
+"<name>"+name+"</name>"//
+"</>person">"//
+"</faxml>";
Sysout(createXml);
get the name in a variable. Hard code these lines and insert it like this..

JAXB: unmarshal diferent xml to same object

I have 3 input XML that have, pretty much, the same elements and attributes, in fact, they represent the same thing, so I want to marshall them to the same object, something like this:
Request One:
<?xml version="1.0" encoding="UTF-8"?>
<RequestOne>
<id>123</id>
<name>foo</name>
</RequestOne>
Request Two:
<?xml version="1.0" encoding="UTF-8"?>
<RequestTwo>
<id>123</id>
<value>val</value>
</RequestTwo>
Request Three:
<?xml version="1.0" encoding="UTF-8"?>
<RequestThree>
<name>foo</name>
<value>val</value>
</RequestThree>
Desired Object (something like):
#XmlRootElement
public class Resource{
#XmlElement
private String id;
#XmlElement
private String name;
#XmlElement
private String value;
//(...) more code
}
But I can't use multiple RootElement annotations to ask JAXB to unmarshall all of the 3 request to objects of the class Resource
Is there a way to do it? Or I must make the 3 sepparated classes?
Thanks for your help
Option 1
Unmarshal using the overloaded Generic unmarshal method :
public static class Base {
private String name ;
#XmlElement(name = "name")
public String getName() {
return name;
}
public Base setName(String name) {
this.name = name;
return this;
}
}
public static void main (String [] args) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(Base.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
JAXBElement<Base> basea = unmarshaller.unmarshal(new StreamSource(new StringReader("<RootA><name>nanana</name></RootA>")), Base.class);
System.out.println(basea.getValue().getName());
JAXBElement<Base> baseb = unmarshaller.unmarshal(new StreamSource(new StringReader("<RootB><name>nbnbnb</name></RootB>")), Base.class);
System.out.println(baseb.getValue().getName());
}
Option 2
You can always use Java's class subtyping capabilites ? JAXB does annotation scanning on parent class as well. This example works
public static class Base {
private String name ;
#XmlElement(name = "name")
public String getName() {
return name;
}
public Base setName(String name) {
this.name = name;
return this;
}
}
#XmlRootElement( name = "RootA")
public static class RootA extends Base{
}
#XmlRootElement( name = "RootB")
public static class RootB extends Base {
}
public static void main (String [] args) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(RootA.class,RootB.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
RootA rootA = (RootA)unmarshaller.unmarshal(new StringReader("<RootA><name>nanana</name></RootA>"));
System.out.println(rootA.getName());
RootB rootB = (RootB)unmarshaller.unmarshal(new StringReader("<RootB><name>nbnbnb</name></RootB>"));
System.out.println(rootB.getName());
}

How to check an integer field in XML has string value in jaxb unmarshaling

I have to check whether I have getting string in integer field in xml when unmarshaling using JAXB.
Implementation Class:
import java.io.IOException;
import javax.xml.bind.JAXB;
public class JAXBDemo {
public static void main(String[] args) throws IOException {
try {
String xmlString = "file:///c:/xml/stud.xml";
// unmarshal XML string to class
Student st = JAXB.unmarshal(xmlString, Student.class);
// prints
System.out.println("Age : "+st.getAge());
System.out.println("Name : "+st.getName());
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
Mapping Class :
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Student{
String name;
int age;
int id;
public String getName(){
return name;
}
#XmlElement
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
#XmlElement
public void setAge(int age){
this.age = age;
}
public int getId(){
return id;
}
#XmlAttribute
public void setId(int id){
this.id = id;
}
}
Input XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<student id="10">
<age>hello</age>
<name>Malik</name>
</student>
Output:
Age : 0
Name : Malik
when I give String value in integer field it gives as zero. I have to check how to check an integer field in xml having non numeric value and throw an error.
JAXB is a convenience class that encompass JAXBContext, Unmarshaller and other JAXB API libraries to make it easier to perform simple operations.
The problem with it, that it's not really dealing with issues like validating the schemas and performance issues. it'll try to do a "best effort" and ignore issues for not matching data fields, such as String in an int field.
in order to circumvent that, you'll have to use the JAXB API directly, and validate the schema during the unmarshaling process.
I haven't tested this code, but it should be something similar to this:
JAXBContext jc = JAXBContext.newInstance(Student.class);
Unmarshaller u = jc.createUnmarshaller();
Student st = u.unmarshal(new File(xmlString));
you might need to explicitly cast the unmarshal to Student, i.e:
Student st = (Student)u.unmarshal(new File(xmlString));

Define XML Structure with Xstream

I need to convert one POJO into the following XML:
<Root>
<Version>2.0</Version>
<Name>John</Name>
<Age>18</Age>
<UserId>22491</UserId>
<Country>USA</Country>
<AnotherData>
<Records>
<AnotherRecord>
<Field1>XXX</Field1>
<Field2>XX</Field2>
<Field3>CCCCCCCC</Field3>
<Field4>XXX9000</Field4>
<Field5>XXX00345</Field5>
</AnotherRecord>
</Records>
</AnotherData>
</Root>
I know how to convert the fields below the root tag, it's not a problem. But from the AnotherData my problem's starting.
To represent the xml above I need some class like this:
puclic class Root{
public String Version;
public String Name;
public String Age;
public String UserID;
public String Country;
public AnotherData AnotherData;
}
public class AnotherData{
public Records Records;
}
public class Records{
List<AnotherRecord> list;
}
public class AnotherRecord{
public String Field1;
public String Field2;
public String Field3;
public String Field4;
public String Field5;
}
But I don't need of this structure of class, I like implement my classes in a more simple mode, and "force" the tag structure in xml.
My class would be like below, but keeping the structure xml like above.
puclic class Root{
public String Version;
public String Name;
public String Age;
public String UserID;
public String Country;
public AnotherData AnotherData;
List<AnotherRecord> list;
}
public class AnotherRecord{
public String Field1;
public String Field2;
public String Field3;
public String Field4;
public String Field5;
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
I do not believe this use case can be handled by XStream. If you are open to using other technologies, below is an example of how it could be done with MOXy. Using the #XmlPath extension.
#XmlPath("AnotherData/Records/AnotherRecord")
List<AnotherRecord> list;
Root
Below is what the fully mapped Root class would look like. JAXB does not require any annotations (see: http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html), but since the XML elements in your document do not match the default naming rules some annotations are required.
package forum11970410;
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="Root")
public class Root{
#XmlElement(name="Version")
public String Version;
#XmlElement(name="Name")
public String Name;
#XmlElement(name="Age")
public String Age;
#XmlElement(name="UserId")
public String UserID;
#XmlElement(name="Country")
public String Country;
#XmlPath("AnotherData/Records/AnotherRecord")
List<AnotherRecord> list;
}
AnotherRecord
package forum11970410;
import javax.xml.bind.annotation.XmlElement;
public class AnotherRecord{
#XmlElement(name="Field1")
public String Field1;
#XmlElement(name="Field2")
public String Field2;
#XmlElement(name="Field3")
public String Field3;
#XmlElement(name="Field4")
public String Field4;
#XmlElement(name="Field5")
public String Field5;
}
jaxb.properties
To specify MOXy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain classes with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
You can use the following demo code to prove that everything works:
package forum11970410;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum11970410/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Version>2.0</Version>
<Name>John</Name>
<Age>18</Age>
<UserId>22491</UserId>
<Country>USA</Country>
<AnotherData>
<Records>
<AnotherRecord>
<Field1>XXX</Field1>
<Field2>XX</Field2>
<Field3>CCCCCCCC</Field3>
<Field4>XXX9000</Field4>
<Field5>XXX00345</Field5>
</AnotherRecord>
</Records>
</AnotherData>
</Root>
For More Information
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2010/10/how-does-jaxb-compare-to-xstream.html

Categories

Resources