The structure
<html>
<span><h1>test</h1></span>
<table>
</table>
</html>
How can i get the text "test" if <span> might be a <div>?
#XmlAccessorType(XmlAccessType.FIELD)
public class HtmlTag {
#XmlElement(name = "h1")
String h1;
}
Unmarshalls to null.
#XmlAccessorType(XmlAccessType.FIELD)
public class HtmlTag
{
#XmlAnyElement
List<org.w3c.dom.Element> elements;
}
get test string
HtmlTag htmlTag = //...
Element firstElement = htmlTag.elements.get(0); // this is first element,
// currently it is <span>
firstElement.getElementsByTagName("h1").item(0).getTextContent(); // return 'test'
You can leverage a StAX StreamFilter on an XMLStreamReader so that the elements you want to ignore are not reported as events. Then you can unmarshal from the XMLStreamReader with JAXB.
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(HtmlTag.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource xml = new StreamSource("src/forum17613060/input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(xml);
xsr = xif.createFilteredReader(xsr, new StreamFilter() {
#Override
public boolean accept(XMLStreamReader reader) {
if(reader.isStartElement() || reader.isEndElement()) {
String localName = reader.getLocalName();
return !"span".equals(localName) && !"div".equals(localName);
}
return true;
}
});
Unmarshaller unmarshaller = jc.createUnmarshaller();
HtmlTag htmlTag = unmarshaller.unmarshal(xsr, HtmlTag.class).getValue();
System.out.println(htmlTag.h1);
}
}
Related
I unmarshal the Document to object as below.
Before that, when parsing XML, use setUserData to store location information for each element.
class MyJaxbAdapter extends XmlAdapter<Object, SubObject> {}
#Override
public UnattendComponent unmarshal(Object v) throws Exception {
Node node = (Node) v; // ElementNSImpl; It's probably a newly created object. Because It is different from the document object given by ownerDocument as SAXSource.
node.getUserData(...) // return NULL
}
}
Document document = ...;
unmarshaller.setAdapter(new MyJaxbAdapter());
MyXMLObject object = unmarshaller.unmarshal(new DOMSource(document), MyXMLObject.class).getValue();
But I can't get UserData inside XmlAdapter's unmarshal method. Is there any way to persist UserData?
Locator information is stored in the properties of Element as shown below.
#Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
Element el = document.createElementNS(usedNamespaceUri, qName);
// ...
el.setUserData(
ElementUserData.class.getName(),
ElementUserData.builder()
.lineNumber(locator.getLineNumber())
.columnNumber(locator.getColumnNumber())
.build(),
null);
}
I need the Locator information (UserData) stored by the above code in the unmarshal of the XmlAdapter.
However, there is no userdata in the node passed as an argument to unmarshal .
Sample Code:
https://github.com/joseph-jclab/jaxb-question-01
Not entirely sure if this is something you are looking for but providing it as a reference so you might get some idea to proceed further:
Sample XML:
<root>
<name>Batman</name>
<year>2008</year>
</root>
Root.class:
#XmlRootElement(name = "root")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
private String name;
private String year;
#XmlJavaTypeAdapter(CustomAdapter.class)
private String after;
private void afterUnmarshal(Unmarshaller m, Object parent) {
after = name;
}
}
CustomAdapter.class:
public class CustomAdapter extends XmlAdapter<String, String> {
#Override
public String unmarshal(String v) throws Exception {
System.out.println("Within Unmarshal : " + v);
return null;
}
#Override
public String marshal(String v) throws Exception {
System.out.println("Within Marshal : " + v);
return null;
}
}
SampleMain.class:
public class SampleMain {
public static void main(String[] args) throws XMLStreamException, JAXBException {
final InputStream inputStream = Unmarshalling.class.getClassLoader().getResourceAsStream("sample.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Root.class).createUnmarshaller();
unmarshaller.setAdapter(new CustomAdapter());
final Root root = unmarshaller.unmarshal(xmlStreamReader, Root.class).getValue();
System.out.println(root.toString());
Marshaller marshaller = JAXBContext.newInstance(Root.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(root, System.out);
}
}
Output:
Root(name=Batman, year=2008, after=Batman)
Within Marshal : Batman
<root>
<name>Batman</name>
<year>2008</year>
</root>
I am trying to simplify the conversion of POJO to XML, but I am facing issues with Class field attributes.
Consider the following XML files
<cat>
<displayTexts>
<displayText language="en">12</displayText>
<displayText language="en">23</displayText>
</displayTexts>
</cat>
And
I have a class
#XmlRootElement(name = "cat")
public class Category{
List<Integer> list;
public List<Integer> getList() {
return list;
}
#XmlElementWrapper(name = "displayTexts")
#XmlElement(name = "displayText")
public void setList(List<Integer> list) {
this.list = list;
}
}
How can I write an adaptor which will produce XML mentioned as above?
Right now it will produce something like below xml ::
<cat>
<displayTexts>
<displayText>12</displayText>
<displayText>23</displayText>
</displayTexts>
</cat>
Note:: I am not allowed to use MoXy. And I know I can achieve this by writing a different class. The question is can we write an adaptor so that I can generalize this attribute thing for any class field?
Although I would still recommend, using a class Instead of Integer to use the value for displayText and it's attribute, but still if you want to achieve without any new class, you can give following a shot using #XmlAnyElement for your displayList and "creating" the xml yourself:
import java.util.Arrays;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
#XmlRootElement(name = "cat")
public class Category {
List<Integer> list;
#XmlAnyElement()
#XmlJavaTypeAdapter(MyIntegerAdapter.class)
public List<Integer> getList() {
return list;
}
//#XmlElement(name = "displayText")
public void setList(List<Integer> list) {
this.list = list;
}
public static void main(String[] args) throws Exception {
Category bx = new Category();
List<Integer> lists = Arrays.asList(121, 212);
bx.setList(lists);
JAXBContext jc = JAXBContext.newInstance(Category.class);
MyIntegerAdapter adapter = new MyIntegerAdapter();
Marshaller marrshaller = jc.createMarshaller();
marrshaller.setAdapter(adapter);
marrshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marrshaller.marshal(bx, System.out);
}
}
class MyIntegerAdapter extends XmlAdapter<Element, List<Integer>> {
private DocumentBuilder documentBuilder;
public MyIntegerAdapter() {
}
private DocumentBuilder getDocumentBuilder() throws Exception {
// Lazy load the DocumentBuilder as it is not used for unmarshalling.
if (null == documentBuilder) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
documentBuilder = dbf.newDocumentBuilder();
}
return documentBuilder;
}
#Override
public Element marshal(List<Integer> lists) throws Exception {
if (null == lists) {
return null;
}
Document document = getDocumentBuilder().newDocument();
Element element = document.createElement("displayTexts");
for (int value : lists) {
Element displayText = document.createElement("displayText");
System.out.println("value.." + value);
displayText.setTextContent(value + "");
displayText.setAttribute("Lang", "en");
element.appendChild(displayText);
}
return element;
}
#Override
public List<Integer> unmarshal(Element v) throws Exception {
//TODO
throw new UnsupportedOperationException();
}
}
I have the following classes with jax-ws webservice;
Interface Class (myserviceInt.java);
#WebService(name="myservice")
#SOAPBinding(style=Style.RPC)
public interface myserviceInt {
#WebMethod(action="urn:OutIn", operationName="ACCT")
public String getACCT(
#WebParam(partName="Prod1")String prod1,
#WebParam(partName="Prod2")String prod2);
}
Implementation Class (myserviceImpl.java);
#WebService(endpointInterface = "path.to.webservice.myserviceInt", portName="acct", serviceName="acctservice", targetNamespace="http://demo.acctservice.com/")
public class myserviceImpl implements myserviceInt {
#Override
public String getACCT(String prod1, String prod1){
Other codes
String id = "25";
String description = "The Third Product"
ACCTResponse acct = new ACCTResponse();
acct.setId(id);
acct.setDescription(description);
String XMLstring = acct.ACCTResponseBeanToXML(acct);
return XMLstring;
}
}
ACCTResponse Class (ACCTResponse.java);
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name="ACCTResponse")
public class ACCTResponse {
#XmlElement(name = "ID")
private String id;
#XmlElement(name = "Description")
private String description;
... their setters and getters;
}
The Marshaller Class (ACCTUtil.java);
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import path.to.responseclass.ACCTResponse;
public class ACCTUtil {
public static String ACCTResponseBeanToXML(ACCTResponse acct)
{
String responseStr = null;
try
{
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(ACCTResponse.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(acct, writer);
responseStr = writer.toString();
int xmlHeaderIndex = responseStr.indexOf("?>");
if(xmlHeaderIndex > 0)
responseStr = responseStr.substring(xmlHeaderIndex + 2, responseStr.length());
}
catch(Exception ex){
ex.printStackTrace();
}
return responseStr;
}
}
every other libraries needed were left out to save time. I also have the package-info.java in the respective path for the ACCTResponse.java to add the required response namespaceURI and prefix.
Now, I got the following as response after Marshalling as described above;
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:ACCTResponse xmlns:ns2="http://demo.acctservice.com/">
<return><![CDATA[<net:ACCTResponse xmlns:net="http://demo.acctservice.com/">
<net:ID>25</net:ID>
<net:Description>The Third Product</net:Description>
</net:ACCTResponse>]]></return>
</ns2:ACCTResponse>
</S:Body>
</S:Envelope>
The response I want to achieve for a consumer of this webservice that have a fixed client is this;
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org /soap/envelope/">
<saop:Body>
<net:ACCTResponse xmlns:net="http://demo.acctservice.com/">
<net:ID>25</net:ID>
<net:Description>The Third Product</net:Description>
</net:ACCTResponse>
</soapenv:Body>
</soapenv:Envelope>
What modifications/manipulations do I need, to achieve this response from my codes. Thanks.
I am trying to create bean from string but unable to create as it is returning null.Here is my code
public ModelAndView checkPhotoQualityRequest(
#RequestBody String photoDataXml, HttpServletRequest request) {
PhotoQuality photoQuality = null;
try {
JAXBContext jaxbContext = JAXBContext
.newInstance(PhotoQuality.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(photoDataXml);
photoQuality = (PhotoQuality) unmarshaller.unmarshal(reader);
PhotoQuality.java
package in.gov.uid.opencvaccess.bean;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(name = "PhotoQuality")
#XmlRootElement(name = "PhotoQuality")
public class PhotoQuality {
private String photoid;
private byte[] photo;
private boolean quality;
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getPhotoid() {
return photoid;
}
public void setPhotoid(String photoid) {
this.photoid = photoid;
}
public byte[] getPhoto() {
return photo;
}
public void setPhoto(byte[] photo) {
this.photo = photo;
}
public boolean isQuality() {
return quality;
}
public void setQuality(boolean quality) {
this.quality = quality;
}
}
Please help me to sort out this issue.When I debug and check bean its showing all null values but photoDataXml showing complete xml.
I have found the reason.When I tried using RESTClient its giving null object. But as soon as I written client code and passed StringWriter value created from PhotoQuality Object then it runs properly.
I have a complex object I'm getting back as a return value from the usual "API I have no control over".
For some API calls the returned XML looks like:
<APICall1>
<VeryComplexObject>
<VeryComplexObjectElements... >
</VeryComplexObject>
</APICall1>
No problem, I just use
#XmlElement
private VeryComplexObject VeryComplexObject;
and it's business as usual.
But a few calls want to return:
<APICall2>
<VeryComplexObjectElements... >
</APICall2>
Is there an annotation I can use to suppress the <VeryComplexObject> tags for unmarshal but get the inner element tags?
You could use JAXB with StAX to accomplish this by leveraging a StreamFilter to ignore an XML element:
package forum8526002;
import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.stream.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
StringReader xml = new StringReader("<APICall2><VeryComplexObjectElements><Bar>Hello World</Bar></VeryComplexObjectElements></APICall2>");
XMLStreamReader xsr = xif.createXMLStreamReader(xml);
xsr = xif.createFilteredReader(xsr, new Filter());
Unmarshaller unmarshaller = jc.createUnmarshaller();
Foo foo = (Foo) unmarshaller.unmarshal(xsr);
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(foo, System.out);
}
#XmlRootElement(name="APICall2")
static class Foo {
#XmlElement(name="Bar")
private String bar;
}
static class Filter implements StreamFilter {
#Override
public boolean accept(XMLStreamReader reader) {
return !(reader.isStartElement() && reader.getLocalName().equals("VeryComplexObjectElements"));
}
}
}