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>