I have different xml files with different namespaces eg - oa, ns2, p...etc
I want the namespace to be ignored when converting the xml back to java object.
or I want the namespace to be removed from the xml when converting the xml to object.
My sample xml data is
<oa:ApplicationArea>
<oa:Sender>
<oa:LogicalId>Volvo</oa:LogicalId>
<oa:Component>DVLA</oa:Component>
<oa:Task>ReceiveKeeper</oa:Task>
<oa:MessageCode>MS1</oa:MessageCode>
<oa:AuthorizationId>SKARUPAI</oa:AuthorizationId>
<oa:OrganisationLevel>50</oa:OrganisationLevel>
</oa:Sender>
<oa:CreationDateTime>2013-08-31T12:00:00</oa:CreationDateTime>
<oa:BODId>123456789</oa:BODId>
</oa:ApplicationArea>
<p:DataArea>
<oa:Sync confirm="Always">
<oa:SyncCriteria expressionLanguage="XPath">
<oa:SyncExpression action="Add"></oa:SyncExpression>
</oa:SyncCriteria>
</oa:Sync>
</p:DataArea>
Below is the sample of the code which I am using to convert the above xml to java using Xstream.
public static void main(String[] args) throws Exception {
FileReader fileReader = new FileReader("C:/kspace/xstream/src/input.out.xml"); // load our xml file
XStream xstream = new XStream(); // init XStream
// Determine type of message(Eg. 'EM1') and put the corresponding value from hashmap to a String.
// Pass the string to xstream.alias(stringnamewhichwasset, xmlRoot.class)
String interfaceMessageId = "MS1";
String xmlRootTagName = (String) messages.get(interfaceMessageId);
xstream.registerConverter(new XMLDateConverter());
xstream.alias(xmlRootTagName, RootType.class);
xstream.aliasField("ApplicationArea", RootType.class, "applicationArea");
xstream.aliasField("DataArea", RootType.class, "dataArea");
xstream.alias("ApplicationArea", ApplicationArea.class);
xstream.aliasField("Sender", ApplicationArea.class, "sender");
xstream.aliasField("CreationDateTime", ApplicationArea.class, "creationDateTime");
xstream.aliasField("BODId", ApplicationArea.class, "bodId");
xstream.alias("Sender", Sender.class);
xstream.aliasField("LogicalId", Sender.class, "logicalId");
xstream.aliasField("Component", Sender.class, "component");
xstream.aliasField("Task", Sender.class, "task");
xstream.aliasField("MessageCode", Sender.class, "messageCode");
xstream.aliasField("AuthorizationId", Sender.class, "authorizationId");
xstream.aliasField("OrganisationLevel", Sender.class, "organisationLevel");......
......
Is there any way to do it with Xstream at all?
Finally got the solution after trying using StaxDriver.
Here is what I did.
QNameMap qmap = new QNameMap();
qmap.setDefaultNamespace("http://www.somename.com/xyz");
qmap.setDefaultPrefix("");
StaxDriver staxDriver = new StaxDriver(qmap);
XStream xstream = new XStream(staxDriver);
Creating the xstream object like that will ignore the namespace prefixes while parsing.
So far I was successfully able to remove all the namespace prefixes.
Related
I have two classes at the moment. Customer and CustomerItem, each Customer can contain multiple CustomerItems:
#XmlRootElement(name = "Customer")
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer implements Serializable {
private final String customerNumber;
private final String customerName;
#XmlElementWrapper(name = "customerItems")
#XmlElement(name = "CustomerItem")
private List<CustomerItem> customerItems;
...
Via REST we can get a List<Customer>, which will result in an XML looking like that:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<collection>
<Customer>
// normal values
<customerItems>
<customerItem>
// normal values
</customerItem>
</customerItems>
</Customer>
<Customer>
...
</Customer>
<Customer>
...
</Customer>
</collection>
Now if I want to unmarshal the response I get an error:
javax.xml.bind.UnmarshalException: unexpected element (uri:"",
local:"collection"). Expected elements are
<{}Customer>,<{}CustomerItem>
private List<Customer> getCustomersFromResponse(HttpResponse response)
throws JAXBException, IllegalStateException, IOException {
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
InputStream content = response.getEntity().getContent();
InputStreamReader reader = new InputStreamReader(content);
java.util.List<Customer> unmarshal = (List<Customer>) jaxbUnmarshaller.unmarshal(reader);
return unmarshal;
}
Now I know why it's not working, obviously Jaxb expects Customer to be the root element, but now find a collection (which seems to be a default value when a List gets returned?).
A workaround would be to create a new Customers class which contains a list of customer and make it the root element, but actually I wouldn't want a new class.
There must be a way to tell jaxb that I have a list of the classes I want to get and that he should look inside the collection tag or something like that?!
I see here two ways.
1) Create special wrapper class with #XmlRootElement(name = "collection") and set it against unmarshaller.
2) Another way - split input xml into smaller one using simple SAX parser implementation and then parse each fragment separately with JAXB (see: Split 1GB Xml file using Java).
I don't think that you can simply tell JAXB: parse me this xml as set of elements of type XXX.
I have an class like below and I use xSteam to convert Edge to xml.
#XStreamAlias("edge")
class Edge{
#XStreamAsAttribute
#XStreamAlias("source")
private String source;
#XStreamAsAttribute
#XStreamAlias("target")
private String target;
#XStreamAlias("data")
private Data data;
.....
}
When I set data=null, i can get
<edge source="8" target="10" />
but I want to get below when data =null
<edge source="8" target="10" ></edge>
Some one can help for this?
you can use Dom4JDriver driver. in that case you can format your xml output
like this code:
OutputFormat outPutFormat = new OutputFormat();
outPutFormat.setLineSeparator("");
outPutFormat.setExpandEmptyElements(true);
outPutFormat.setEncoding("UTF-8");
Dom4JDriver d4j = new Dom4JDriver(new XmlFriendlyNameCoder("_", "_"));
d4j.setOutputFormat(outPutFormat);
XStream xstream = new XStream(d4j);
xstream.autodetectAnnotations(true);
There is nothing you can do on the XML level, as on that level, both forms are completely identical. If you really really require one form instead of the other, you have to either provide your own XML serializer, or use the default serializer and post-process its output stream. i cannot give you more details without knowing how you currently serialize your data.
I'm trying to create a SAML response. One of the attributes that makes up the assertion is called address and the attribute value needs to be a custom type that is defined in an XSD. How do I add custom attribute value types to the response?
If your attribute value XML is in String form:
String yourXMLFragment = "...";
AttributeStatementBuilder attributeStatementBuilder =
(AttributeStatementBuilder) builderFactory.getBuilder(AttributeStatement.DEFAULT_ELEMENT_NAME);
AttributeStatement attributeStatement = attributeStatementBuilder.buildObject();
AttributeBuilder attributeBuilder =
(AttributeBuilder) builderFactory.getBuilder(Attribute.DEFAULT_ELEMENT_NAME);
Attribute attr = attributeBuilder.buildObject();
attr.setName("yourAttributeName");
XSAnyBuilder sb2 = (XSAnyBuilder) builderFactory.getBuilder(XSAny.TYPE_NAME);
XSAny attrAny = sb2.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSAny.TYPE_NAME);
attrAny.setTextContent(yourXMLFragment.trim());
attr.getAttributeValues().add(attrAny);
attributeStatement.getAttributes().add(attr);
Actually this above does not yeld correct results. The above example can be used only to create xsany with text content not xml content (xml content gets escaped).
So after digging in opensaml sources the following did work as needed:
public XSAny createXSAny(Element dom)
{
XSAnyBuilder anyBuilder = (XSAnyBuilder) Configuration.getBuilderFactory().getBuilder(XSAny.TYPE_NAME);
XSAny any = anyBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSAny.TYPE_NAME);
// this builds only the root element not the whole dom
XSAny xo=anyBuilder.buildObject(dom);
// set/populate dom so whole dom gets into picture
xo.setDOM(dom);
any.getUnknownXMLObjects().add(xo);
return any;
}
jdom seems to remove duplicate namespace declarations. This is a problem when a XML document is embedded into another XML structure, such as for example in the OAI-PHM (open archive initiative). This can be a problem when the surrounding xml is only a container and the embedded document gets extracted later.
Here is some code. The embedded xml is contained in the string with the same name. It declares the xsi namespace. We construct a jdom container, also declaring the xsi namespace. We parse and embed the string. When we print the whole thing the inner xsi namepsace is gone.
public static final Namespace OAI_PMH= Namespace.getNamespace( "http://www.openarchives.org/OAI/2.0/");
public static final Namespace XSI = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
public static final String SCHEMA_LOCATION = "http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd";
public static final String ROOT_NAME = "OAI-PMH";
String embeddedxml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <myxml xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\""
+ "http://www.isotc211.org/2005/gmd"
+ " http://www.ngdc.noaa.gov/metadata/published/xsd/schema/gmd/gmd.xsd"
+ " http://www.isotc211.org/2005/gmx"
+ " http://www.ngdc.noaa.gov/metadata/published/xsd/schema/gmx/gmx.xsd\">\""
+ "</myxml>";
// loadstring omitted (parse embeddedxml into jdom)
Element xml = loadString(embeddedxml ,false);
Element root = new Element(ROOT_NAME, OAI_PMH);
root.setAttribute("schemaLocation", SCHEMA_LOCATION, XSI);
// insert embedded xml into container structure
root.addContent(xml);
XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
// will see that the xsi namespace declaration from embeddedxml is gone
out.output(root,System.out);
I think that XMLoutputter is responsible for this behaviour. Any hints how I can make it preserve the duplicate namepspace?
thanks
Kurt
Something is missing in your code: The declaration of final static String ROOT_NAME is not shown and Element xml ist not used after initialization.
If ROOT_NAME is initialized with "myxml" somewhere else, then the solution to your problem is, that you just don't add the xml element to your document, and the result looks as if you did so.
My goal is to take an XML string and parse it with XMLBeans XmlObject and add a few child nodes.
Here's an example document (xmlString),
<?xml version="1.0"?>
<rootNode>
<person>
<emailAddress>joefoo#example.com</emailAddress>
</person>
</rootNode>
Here's the way I'd like the XML document to be after adding some nodes,
<?xml version="1.0"?>
<rootNode>
<person>
<emailAddress>joefoo#example.com</emailAddress>
<phoneNumbers>
<home>555-555-5555</home>
<work>555-555-5555</work>
<phoneNumbers>
</person>
</rootNode>
Basically, just adding the <phoneNumbers/> node with two child nodes <home/> and <work/>.
This is as far as I've gotten,
XmlObject xml = XmlObject.Factory.parse(xmlString);
Thank you
Here is an example of using the XmlCursor to insert new elements. You can also get a DOM Node for an XmlObject and using those APIs.
import org.apache.xmlbeans.*;
/**
* Adding nodes to xml using XmlCursor.
* #see http://xmlbeans.apache.org/docs/2.4.0/guide/conNavigatingXMLwithCursors.html
* #see http://xmlbeans.apache.org/docs/2.4.0/reference/org/apache/xmlbeans/XmlCursor.html
*/
public class AddNodes
{
public static final String xml =
"<rootNode>\n" +
" <person>\n" +
" <emailAddress>joefoo#example.com</emailAddress>\n" +
" </person>\n" +
"</rootNode>\n";
public static XmlOptions saveOptions = new XmlOptions().setSavePrettyPrint().setSavePrettyPrintIndent(2);
public static void main(String[] args) throws XmlException
{
XmlObject xobj = XmlObject.Factory.parse(xml);
XmlCursor cur = null;
try
{
cur = xobj.newCursor();
// We could use the convenient xobj.selectPath() or cur.selectPath()
// to position the cursor on the <person> element, but let's use the
// cursor's toChild() instead.
cur.toChild("rootNode");
cur.toChild("person");
// Move to </person> end element.
cur.toEndToken();
// Start a new <phoneNumbers> element
cur.beginElement("phoneNumbers");
// Start a new <work> element
cur.beginElement("work");
cur.insertChars("555-555-5555");
// Move past the </work> end element
cur.toNextToken();
// Or insert a new element the easy way in one step...
cur.insertElementWithText("home", "555-555-5555");
}
finally
{
if (cur != null) cur.dispose();
}
System.out.println(xobj.xmlText(saveOptions));
}
}
XMLBeans seems like a hassle, here's a solution using XOM:
import nu.xom.*;
Builder = new Builder();
Document doc = builder.build(new java.io.StringBufferInputStream(inputXml));
Nodes nodes = doc.query("person");
Element homePhone = new Element("home");
homePhone.addChild(new Text("555-555-5555"));
Element workPhone = new Element("work");
workPhone.addChild(new Text("555-555-5555"));
Element phoneNumbers = new Element("phoneNumbers");
phoneNumbers.addChild(homePhone);
phoneNumbers.addChild(workPhone);
nodes[0].addChild(phoneNumbers);
System.out.println(doc.toXML()); // should print modified xml
It may be a little difficult to manipulate the objects using just the XmlObject interface. Have you considered generating the XMLBEANS java objects from this xml?
If you don't have XSD for this schema you can generate it using XMLSPY or some such tools.
If you just want XML manipulation (i.e, adding nodes) you could try some other APIs like jdom or xstream or some such thing.
Method getDomNode() gives you access to the underlying W3C DOM Node. Then you can append childs using W3C Document interface.