Jaxb marshal different namespaces with recursive one - java

I want to marshal into xml like this:
<?xml version='1.0' encoding='UTF-8'?>
<ns1:rootElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="some_location" xmlns:ns1="namespace1"
xmlns:ns2="namespace2">
<ns1:firstElement>some text</ns1:firstElement>
<ns1:secondElement>
<ns2:otherElement>some text</ns2:otherElement>
...
<ns2:nElement>
<ns2:innerElement>
<ns2:otherInnerElement>some text</ns2:otherInnerElement>
</ns2:innerElement>
</ns2:nElement>
</ns1:secondElement>
</ns1:rootElement>
There are 2 namespaces. The first one is only for rootElement and direct root element. The second namespace is for other huge number of elements with recursion.
How can I describe this without annotating each elements (tags) for namespace2?

I put root class in one package with package-info like that:
#XmlSchema(
namespace = "namespace1",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(prefix = "ns1", namespaceURI = "namespace1")
}
)
And other classes I put in another package with own package-info:
#XmlSchema(
namespace = "namespace2",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(prefix = "ns2", namespaceURI = "namespace2")
}
)

Related

xmlns attribute missing for element when marshalling with JAXB

Currently xml generated after marshalling which is missing the xmlns attribute for ColumnAlias:
<ns5:Environment xmlns:ns2="http://www.analytixds.com/amm/xml/systemmanager/v1/extendedproperties" xmlns:ns3="http://www.analytixds.com/amm/xml/systemmanager/v1/columns" xmlns:ns4="http://www.analytixds.com/amm/xml/systemmanager/v1/tables" xmlns:ns5="http://www.analytixds.com/amm/xml/systemmanager/v1/environments">
<ns4:Tables version="12">
<ns4:Table>
<ns3:Columns version="12">
<ns3:Column>
<ColumnAlias></ColumnAlias>
I am trying to set xmlns attribute for ColumnAlias Element so that output would be
<ns5:Environment xmlns:ns2="http://www.analytixds.com/amm/xml/systemmanager/v1/extendedproperties" xmlns:ns3="http://www.analytixds.com/amm/xml/systemmanager/v1/columns" xmlns:ns4="http://www.analytixds.com/amm/xml/systemmanager/v1/tables" xmlns:ns5="http://www.analytixds.com/amm/xml/systemmanager/v1/environments">
<ns4:Tables version="12">
<ns4:Table>
<ns3:Columns version="12">
<ns3:Column>
<ColumnAlias xmlns="http://www.stuff.com"></ColumnAlias>
My Domain class:
#XmlRootElement(name = "Column")
public class Column {
#XmlElement(name = "ColumnAlias", required = true,namespace="http://www.stuff.com")
protected String columnAlias;
I suppose it's common that namespace="http://www.stuff.com" must add namespace to its parent element "Column" and appropriate prefix to child element "columnAlias".
So turns out the xml that was being produced was also valid wrt to the schema and did not need the extra xmlns="http://www.stuff.com".

remove prefix from XML in JAXB

I'm trying to generate an XML file with JAXB Annotations
So, i'll generate the JAXB Classes & the package-info.java from the XSD
Lets go :
1 - Package-info.java
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2017.01.05 at 01:51:40 PM CET
//
#XmlSchema(
xmlns = {
#XmlNs(namespaceURI = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2", prefix = "cac"),
#XmlNs(namespaceURI = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2", prefix = "cbc"),
#XmlNs(namespaceURI = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2", prefix = "") //this must be empty prefix
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.audaxis.compiere.osg.ei.ubl2;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlSchema;
2 - then I generate an XML with the folowing code :
JAXBContext context = JAXBContext.newInstance(InvoiceType.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
m.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, TUEInvoiceConstants.UBLInvoiceShcemaLocation);
// Write to File
File f = new File(System.getProperty("java.io.tmpdir"), getOutputFileNameSimple(root));
m.marshal(root, f);
3 - result Generated XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Invoice
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:ns11="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xsi:schemaLocation="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2 UBL-Invoice-2.1.xsd">
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<-- XML tags -->
<END XML>
4 - As you can see, the third namespace was created with a prefix = ns11 , this will cause problems for me in the next step.
Question : How can i let it generate the XML without any prefixes ??

DocumentBuilder.parse raises the error "The prefix "c" for element "c:de" is not bound."

I am getting the error "The prefix "c" for element "c:de" is not bound." Any clue will be very appreciated.
javax.xml.parsers.DocumentBuilderFactory fac = new org.apache.xerces.jaxp.DocumentBuilderFactoryImpl( );
fac.setNamespaceAware(true);
org.w3c.dom.Document d = null;
javax.xml.parsers.DocumentBuilder builder = fac.newDocumentBuilder();
d = builder.parse("C:/my_folder/my_file.xml"); //the error rises in this line
my_file.xml is exactly and complete pasted here.
<?xml version="1.0" encoding="UTF-8"?>
<c:de format="N" lengthField="0" maxLength="012" minLength="012" name="AMOUNT, TRANSACTION" number="004" subFields="00"/>
Your XML is technically invalid.
The namespace prefix c "MUST be associated with a namespace URI reference in a namespace declaration." (W3). For example, this would work:
<?xml version="1.0" encoding="UTF-8"?>
<c:de xmlns:c="http://localhost/" format="N" lengthField="0" maxLength="012" minLength="012" name="AMOUNT, TRANSACTION" number="004" subFields="00"/>
Note the addition of the xmlns:c attribute. The URI you use in this attribute should be the one that properly identifiies the namespace you intend to use.

Dom4j xmlns attribute

I want to add xmlns attribute to the root node only, however when i add a namespace to the root element, all subsequent child elements also get the same xmlns attribute. How do I add xmlns attribute to a single node but not any of its children ?
CODE:
public String toXml() {
Document document = DocumentHelper.createDocument();
Element documentRoot = document.addElement("ResponseMessage");
documentRoot.addNamespace("",getXmlNamespace())
.addAttribute("xmlns:xsi", getXmlNamespaceSchemaInstance())
.addAttribute("xsi:schemaLocation", getXmlSchemaLocation())
.addAttribute("id", super.getId());
Element header = documentRoot.addElement("Header");
buildHeader(header);
Element body = documentRoot.addElement("Body");
buildProperties(body);
body.addElement("StatusMessage").addText(this.getStatusMessage().getMessage());
return document.asXML();
}
OK, new answer.
If you want your elements to belong to a certain namespace, be sure to create them in that namespace. Use the methods that have Qname as one of its arguments. If you create an element with no namespace, DOM4J will have to add namespace declarations to accommodate to your (unwillingly) specification.
Your example slightly edited. I didn't use QName, but gave each element a namespace uri:
public static String toXml() {
Document document = DocumentHelper.createDocument();
Element documentRoot = document.addElement("ResponseMessage",
getXmlNamespace());
documentRoot.addAttribute(QName.get("schemaLocation", "xsi", "xsi-ns"),
"schema.xsd").addAttribute("id", "4711");
Element header = documentRoot.addElement("Header");
Element body = documentRoot.addElement("Body", getXmlNamespace());
// buildProperties(body);
body.addElement("StatusMessage", getXmlNamespace()).addText("status");
return document.asXML();
}
private static String getXmlNamespace() {
return "xyzzy";
}
public static void main(String[] args) throws Exception {
System.out.println(toXml());
}
produces as output:
<?xml version="1.0" encoding="UTF-8"?>
<ResponseMessage xmlns="xyzzy" xmlns:xsi="xsi-ns" xsi:schemaLocation="schema.xsd" id="4711">
<Header/><Body><StatusMessage>status</StatusMessage></Body>
</ResponseMessage>
UPDATE 2:
Note also, that I changed the way how the schemaLocation attribute is declared. You really never have to manually manage the namespace declarations--this will be taken care of by the library.
However, there is one case where it might be useful to add a namespace delaration: If you have a document with predominantly namespace X elements, and some child elements with namspace Y spread out in the document, declaring a namesapce binding for Y at the root element, may save a lot of repeating name space declarations in the child elements.
Heres how. Its a bit of a hack, but it does what you want:
public static String toXml() {
Document d = DocumentHelper.createDocument();
Namespace rootNs = new Namespace("", DEFAULT_NAMESPACE); // root namespace uri
Namespace xsiNs = new Namespace("xsi", XSI_NAMESPACE); // xsi namespace uri
QName rootQName = QName.get(rootElement, rootNs); // your root element's name
Element root = d.addElement(rootElement);
root.setQName(rootQName);
root.add(xsiNs);
root.addAttribute("xsi:schemaLocation", SCHEMA_LOC)
.addAttribute("id", super.getId());
Element header = documentRoot.addElement("Header");
Element body = documentRoot.addElement("Body", getXmlNamespace());
// buildProperties(body);
body.addElement("StatusMessage", getXmlNamespace()).addText("status");
return document.asXML();
}

ready made parser in java

i have some user defined tag. for example data here , jssj .I have a file(not xml) which contains some data embeded in tags.I need a parser for this which will identify my tags and will extract the data in proper format.
Eg
<newpage> thix text </newpage>
<tagD>
<tagA> kk</tagA>
</tagD>
tags can also have some attributes as simlar to html tags. Eg
<mytag height="f" width ="d" > bla bla bla </mytag>
<mytag attribute="val"> bla bla bla</mytag>
You could look at a parser generator like antlr.
Unless your tag syntax can be represented with a (simple) regular grammar (in which case you could try to scan the file with regexes), you will need a proper parser. It is actually not very hard to do at all - just the first time tastes like biting bullets...
You can use JAXB, already included in Java. It's quite simple.
First you need to create a binding to your XML code. The binding provides a map between Java objects and the XML code.
An example would be:
#XmlRootElement(name = "YourRootElement", namespace ="http://someurl.org")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"intValue",
"stringArray",
"stringValue"}
)
public class YourBindingClass {
protected int intValue;
#XmlElement(nillable = false)
protected List<String> stringArray;
#XmlElement(name = "stringValue", required = true)
protected String stringValue;
public int getIntValue() {
return intValue;
}
public void setIntValue(int value) {
this.intValue = value;
}
public List<String> getStringArray() {
if (stringArray == null) {
stringArray = new ArrayList<String>();
}
return this.stringArray;
}
public String getStringValue() {
return stringValue;
}
public void setStringValue(String value) {
this.stringValue = value;
}
}
Then, to encode your Java objects into XML, you can use:
YourBindingClass yourBindingClass = ...;
JAXBContext jaxbContext = JAXBContext.newInstance(YourBindingClass.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
/** If you need to specify a schema */
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new URL("http:\\www.someurl.org"));
marshaller.setSchema(schema);
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, true);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
marshaller.marshal(yourBindingClass, stream);
System.out.println(stream);
To parse your XML back to objects:
InputStream resourceAsStream = ... // Your XML, File, etc.
JAXBContext jaxbContext = JAXBContext.newInstance(YourBindingClass.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object r = unmarshaller.unmarshal(resourceAsStream);
if (r instanceof YourBindingClass) ...
Example starting from a Java object:
YourBindingClass s = new YourBindingClass();
s.setIntValue(1);
s.setStringValue("a");
s.getStringArray().add("b1");
s.getStringArray().add("b2");
// marshal ...
Result:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:YourRootElement xmlns:ns2="http://someurl.org">
<intValue>1</intValue>
<stringArray>b1</stringArray>
<stringArray>b2</stringArray>
<stringValue>a</stringValue>
</ns2:YourRootElement>
If you don't know the input format, that means you probably don't have a XML schema. If you don't have a schema you don't have some it's benefits such as:
It is easier to describe allowable document content
It is easier to validate the correctness of data
It is easier to define data facets (restrictions on data)
It is easier to define data patterns (data formats)
It is easier to convert data between different data types
Anyway, the previous code also works with XML code that contains 'unknown' tags. However your XML code still have to present the required fields and follow the declared patterns.
So the following XML code is also valid. The only restriction is: the tag 'stringValue' should be there. Note that 'stringArrayQ' was not previously declared.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:YourRootElement xmlns:ns2="http://someurl.org">
<stringValue>a</stringValue>
<stringArrayQ>b1</stringArrayQ>
</ns2:YourRootElement>
Are these XML tags? If so, look into one of the many Java XML libraries already available. If they're some kind of custom tagging format, then you're just going to have to write it yourself.
For xml tags - use DOM parser or SAX parser.
You example is XML with this modification:
<root>
<newpage> thix text </newpage>
<tagD>
<tagA> kk</tagA>
</tagD>
</root>
You can use any XML parser you want to parse it.
Edit:
Attributes are a normal part of XML.
<root>
<newpage> thix text </newpage>
<tagD>
<tagA> kk</tagA>
</tagD>
<mytag height="f" width ="d" > bla bla bla </mytag>
<mytag attribute="val"> bla bla bla</mytag>
</root>
Every XML parser can deal with them.
Edit:
If you were able to use Python, you could do something like this:
import lxml.etree
doc = lxml.etree.parse("foo.xml")
print doc.xpath("//mytag[1]/#width")
# => ['d']
That's what i call simple.

Categories