I have a Customer class and also an related xml file to it .
File file = new File("D:\\TestingData\\customer.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Customer data = (Customer) jaxbUnmarshaller.unmarshal(file);
I need to place the customer.xml file in an external location . (D:\TestingData\customer.xml)
My question is that can i supply the xml file as part of String to the unmarshall Method ??
can i supply the xml file as part of String
Yes, you just need to wrap it in a StringReader.
String xml = "<foo><bar>Hello World</bar></foo>";
StringReader reader = new StringReader(xml);
Foo foo = (Foo) unmarshaller.unnmarshal(reader);
Related
I have a pojo class where return type of variable is JAXBElement<String>. I want to store it in a String. Can someone explain how to do it?
File file = new File("C:/Users/Admin/Desktop/JubulaXMLFiles/DemoWithDrools_1.0.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Content.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Content e=(Content) jaxbUnmarshaller.unmarshal(file);
String retrivedValue = (String)e.getProject().getName().toString();
System.out.println(retrivedValue);
Output is like javax.xml.bind.JAXBElement#5a99da. But I want to retrieve the string value in retrivedValue.
If getProject() returns the type JAXBElement<String> then getName() returns the name of the XML tag. To get the value of that element you need to call getValue().
Find below a small snippet
QName qualifiedName = new QName("", "project");
JAXBElement<String> project = new JAXBElement<>(qualifiedName,
String.class, null, "funnyCoding");
System.out.printf("getName() - %s%n", project.getName());
System.out.printf("getValue() - %s%n", project.getValue());
output
getName() - project
getValue() - funnyCoding
I need to implement generics with Antlr4. In order to do this, I need to be able to take a class and, as it is used, dynamically generate code for it like a macro, tokenize that code, generate a tree, and then add that new tree to my original parse tree.
I saw these two classes
http://www.antlr.org/api/JavaTool/org/antlr/v4/runtime/RuleContext.html
http://www.antlr.org/api/JavaTool/org/antlr/v4/runtime/ParserRuleContext.html
However, I'm not sure what they actually do, nor am I sure how to use the constructor.
ParserRuleContext(ParserRuleContext parent, int invokingStateNumber)
RuleContext(RuleContext parent, int invokingState)
Specifically, are these the classes that will represent the new tree, and what should I pass into invokingState/invokingStateNumber?
Apparently it is as easy as this
When walking the first tree, it correctly displays information from both files.
public class Program
{
private static ParserRuleContext getTree(String file) throws Exception
{
InputStream input = new FileInputStream(file);
Reader reader = new InputStreamReader(input);
ANTLRInputStream inputStream = new ANTLRInputStream(reader);
JavaLexer lexer = new JavaLexer(inputStream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
JavaParser parser = new JavaParser(tokens);
ParserRuleContext tree = parser.compilationUnit(); // parse
return tree;
}
public static void main(String args[]) throws Exception
{
ParserRuleContext tree1 = getTree("E:\\Users\\nessy\\IdeaProjects\\AntlrTest\\src\\in1.java");
ParserRuleContext tree2 = getTree("E:\\Users\\nessy\\IdeaProjects\\AntlrTest\\src\\in2.java");
tree1.addChild(tree2);
ParseTreeWalker walker = new ParseTreeWalker(); // create standard walker
JavaWalker extractor = new JavaWalker();
walker.walk(extractor, tree1); // initiate walk of tree with listener
}
}
With this object for example :
public class Person {
#XmlAttribute
private String name = null;
#XmlElement
private Address address = null;
// getters and setters
}
XML file :
<person name="blabla">
<address>...</address>
</person>
What can I do if I want to load a complete Person object (name + address) when umarshalling but only saving its name when marshalling ? (i.e. not saving the address)
The easiest would be to make a copy and remove unnecessary data.
Another (much more complicated option) option would be to defined different mappings. This is possible with MOXy:
Map<String, Object> tenantOneProps = new HashMap<String, Object>();
ArrayList tenantOneBindings = new ArrayList();
tenantOneBindings.add("examples/virtual/base-bindings.xml");
tenantOneBindings.add("examples/virtual/binding-tenant1.xml");
tenantOneProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantOneBindings);
JAXBContext tentantOneContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantOneProps);
Map<String, Object> tenantTwoProps= new HashMap<String, Object>();
ArrayList tenantTwoBindings = new ArrayList();
tenantTwoBindings.add("examples/virtual/base-bindings.xml");
tenantTwoBindings.add("examples/virtual/binding-tenant2.xml");
tenantTwoProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantTwoBindings);
JAXBContext tentantTwoContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantTwoProps);
Here you define two sets of mappings - base plus either tenant1 or tenant2. Thus you create two contexts. You can unmarshal with one and marshal with another.
class foo
{
public static List parse(String input_xml)
{
try {
// JAXB context created.
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
ByteArrayInputStream input = new ByteArrayInputStream(input_xml.getBytes());
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
// Error comes while unmarshalling the input
Root root = (Root) jaxbUnmarshaller.unmarshal(input);
HashMap<String,String> map1 = new HashMap<String,String>();
//... Code to retrieve values from "root" and put it in list
}
}
public static void main(String[] args)
{
String input= "<?xml version=\"1.0\"?>"
+"<root>"
+"<attribs R:SSB:12 = \"ABC\"/>" +
"</root>";
List list = parse(input);
}
}
"attribs" can contains multiple "attributes-value" pairs, hence i need to "UNMARSHAL" it using Jaxb.
I tried using QName , but its throwing error.
Question : While parsing , I am getting this error : "An invalid second ':' was found in the element type or attribute name." .... But i couldn't find any help .... attribute name and values are dynamic in my case.
Thanks for any help!!!*/
The problem is that you are trying to feed JAXB with invalid XML:
<attribs R:SSB:12 = "ABC">
Colon symbol has special meaning in XML: it separates namespace and attribute (or tag) name under that namespace. That's why attribute (or tag) can only contain one colon.
If your attribute names are coming from elsewhere, you have to escape colons to make them valid XML attributes. Try replacing colons with dash symbol (-), for example:
<attribs R-SSB-12="ABC">
The extra : is causing problems as by default JAXB expects the portion behind the : is the namespace prefix. You can solve this by forcing JAXB to use a parser that is not namespace aware.
This can easily be done with a SAX parser and leveraging JAXB's UnmarshallerHandler as the ContentHandler.
Full Example
java xml annotation get field with namespace, <aaa:bbb>value</aaa:bbb>
I am considering using JAXB for XML parsing but I'm having a couple of issues so far that lead me to believe that it might not be flexible enough for what I want.
I'll be parsing XML that is provided by third parties to conform to an XSD that I'll publish. So I want to be flexible enough to handle files that don't have namespaces or specify an old version of the namespace and may in fact contain invalid elements.
Is this sort of flexibility possible with JAXB? At the moment it fails to parse if the namespace is not provided.
How flexible is JAXB?
Very
So I want to be flexible enough to handle files that don't have
namespaces or specify an old version of the namespace and may in fact
contain invalid elements.
NamespaceFilter
Below is a SAX XmlFilter that can be used to apply a missing namespace.
import org.xml.sax.*;
import org.xml.sax.helpers.XMLFilterImpl;
public class NamespaceFilter extends XMLFilterImpl {
private static final String NAMESPACE = "http://www.example.com/customer";
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(NAMESPACE, localName, qName);
}
#Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
super.startElement(NAMESPACE, localName, qName, atts);
}
}
Demo
Below is an example of how you can apply the SAX XMLFilter with JAXB.
import javax.xml.bind.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
public class Demo {
public static void main(String[] args) throws Exception {
// Create the JAXBContext
JAXBContext jc = JAXBContext.newInstance(Customer.class);
// Create the XMLFilter
XMLFilter filter = new NamespaceFilter();
// Set the parent XMLReader on the XMLFilter
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
filter.setParent(xr);
// Set UnmarshallerHandler as ContentHandler on XMLFilter
Unmarshaller unmarshaller = jc.createUnmarshaller();
UnmarshallerHandler unmarshallerHandler = unmarshaller
.getUnmarshallerHandler();
filter.setContentHandler(unmarshallerHandler);
// Parse the XML
InputSource xml = new InputSource("src/blog/namespace/sax/input.xml");
filter.parse(xml);
Customer customer = (Customer) unmarshallerHandler.getResult();
}
}
For More Information
http://blog.bdoughan.com/2012/11/applying-namespace-during-jaxb-unmarshal.html