How to get value with JXPathContext if xmlns specified? - java

final SAXBuilder builder = new SAXBuilder();
final Document xml = builder.build( file );
final Element root = (Element) xml.getRootElement();
Element child = root.getChild("Header", Namespace.getNamespace("http://www.editeur.org/icedis/claims"));
final XPathContext ctx = XPathContext.create(root);
This is the code I have. XPathContext is just wrapper around JXPathContext. As you see, 'child' variable using construction with Namespace and it won't work if I remove it.
But now I'm trying to get value from XML with XPath like this
ctx.getValue("/Header/SentDateTime")
And, ofcourse it always return null. It seems that solution is simple, but I can't find it in the internet. If I delete xmlns from XML file, everything will work, but this isn't an option. So how should I work with this xml?
Also, short version of XML file:
<?xml version="1.0" encoding="UTF-8"?>
<ICEDISClaimMessage version="0.1" xmlns="http://www.editeur.org/icedis/claims">
<Header>
<Sender>
<SenderIdentifier>
<SenderIDType>06</SenderIDType>
<IDValue>1234567890128</IDValue>
</SenderIdentifier>
<SenderName>Apogee Agency</SenderName>
</Sender>
<Addressee>
<AddresseeIdentifier>
<AddresseeIDType>06</AddresseeIDType>
<IDValue>2345678901237</IDValue>
</AddresseeIdentifier>
</Addressee>
<MessageNumber>111</MessageNumber>
<SentDateTime>20101001</SentDateTime>
<MessageNote>Sample file 1: a claim made by an agent to a publisher for a journal issue not yet delivered</MessageNote>
</Header>
</<ICEDISClaimMessage>

You need to use an XPath expression with a namespace context. It would have to look something like this:
final XPathContext ctx = XPathContext.create(root);
ctx.addNamespaceMapping("ns", "http://www.editeur.org/icedis/claims");
... = ctx.getValue("/ns:Header/ns:SentDateTime");
NB: I don't know whether JXPath supports namespaces, and if it does, how it is set up.
And, by the way, it looks like you are using JDOM (SAXBuilder). In that case I would recommend using the JDOM built in XPath functions instead of building a wrapper.

Related

How to set xmlns attribute value in Java Compute Node?

I was trying to propagate the following xml message to the File Output Node in IBM Integration Bus.
<Resto xmlns = 'https://stackoverflow.com'><Location network_id="5dfweg68h"><Category>Continental</Category></Location></Resto>
Following was my associated Java code to construct the above xml message:
MbElement xmlBody = outMessage.getRootElement().createElementAsLastChild(MbXMLNSC.PARSER_NAME);
MbElement xmlParent = xmlBody.createElementAsLastChild(MbElement.TYPE_NAME, "Resto", null);
xmlParent.createElementAsLastChild(MbXMLNSC.ATTRIBUTE, "xmlns", "https://stackoverflow.com");
MbElement locationParser = xmlParent.createElementAsLastChild(MbElement.TYPE_NAME, "Location", null);
locationParser.createElementAsLastChild(MbXMLNSC.ATTRIBUTE, "network_id", "5dfweg68h");
locationParser.createElementAsLastChild(MbElement.TYPE_NAME_VALUE,"Category","Continental");
On debugging my application, I got XML write errors. I pondered a bit for the necessary solution, and found that adding namespace prefix would solve the problem. Can't it be done without the addition of a prefix? If no, can anyone guide me, in assigning the necessary value by suggesting the necessary changes to be done in Java compute node?
Note: The string assigned to xmlns should be within single quotes in the xml message.
Use constant MbXMLNSC.NAMESPACE_DECLARATION to declare the namespace:
MbElement xmlBody = outMessage.getRootElement().createElementAsLastChild(MbXMLNSC.PARSER_NAME);
MbElement xmlParent = xmlBody.createElementAsLastChild(MbElement.TYPE_NAME, "Resto", null);
xmlParent.createElementAsFirstChild(MbXMLNSC.NAMESPACE_DECLARATION, "xmlns", "https://stackoverflow.com");
If your XSD defines that the XML elements are qualified, you have to set the namespace explicitly. Examples:
xmlParent.setNamespace("https://stackoverflow.com");
locationParser.setNamespace("https://stackoverflow.com");
locationParser.createElementAsLastChild(MbElement.TYPE_NAME_VALUE,
"Category", "Continental").setNamespace("https://stackoverflow.com");

How can i modify xml-stylesheet attribute value in java

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet href="Sample.xsl" type="text/xsl"?>
<MyDoc>.....</MyDoc>
I want to modify the attribute href's value to 'MyDoc.xsl'. I have tried using XPath but it returns nothing:
//xml-stylesheet[contains(text(), 'Sample.xsl')]/#href";
Also using Document only gives elements starting at MyDoc
NodeList list = taggedC32Doc.getElementsByTagName("*");
Is there any way i can do this?
The line you want to change is a Processing Instruction, not an Element, so neither of your attempts to find it as an element will work. Try
/processing-instruction(xml-stylesheet)
You can then get that node's data, which will be href="Sample.xsl" type="text/xsl". Perform the appropriate string manipulation to find and change the href pseudo-attribute in that string -- sorry, most XML APIs don't provide any assistance in doing so, because as far as XML is concerned the PI's data is an unformatted string even though it's usually structured to resemble attributes -- and set the new data back into the ProcessingInstruction node.

dom4j XML declaration in document

I need to remove XML declaration from dom4j document type
I am creating document by
doc = (Document) DocumentHelper.parseText(someXMLstringWithoutXMLDeclaration);
String parsed to Document doc by DocumenHelper contains no XML declaration (it comes from XML => XSL => XML transformation)
I think that DocumentHelper is adding declaration to a document body ?
Is there any way to remove XML declaration from the body of
doc
The simpler solution I choose is
doc.getRootElement().asXML();
I'm not sure where exactly this the declaration is a problem in your code.
I had this once when I wanted to write an xml file without declaration (using dom4j).
So if this is your use case: "omit declaration" is what you're looking for.
http://dom4j.sourceforge.net/dom4j-1.6.1/apidocs/org/dom4j/io/OutputFormat.html
Google says this can be set as a property as well, not sure what it does though.
You need to interact with the root element instead of the document.
For example, using the default, compact OutputFormat mentioned by PhilW:
Document doc = (Document) DocumentHelper.parseText(someXMLstringWithoutXMLDeclaration);
final Writer writer = new StringWriter();
new XMLWriter(writer).write(doc.getRootElement());
String out = writer.toString();

if XML file has "xmlns",how can I get Text from XML file using XPath

I get a XML file from website (http://www.abc.com/),
URL is: http://www.abc.com/api/api.xml
content is:
<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://www.abc.com/">
<name>Hello!</name>
</root>
it has xmlns="http://www.abc.com/" in XML file,
now, I using JDOM XPath to get text Hello!
XPath xpath = XPath.newInstance("/root/name/text()");
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new URL("http://www.abc.com/api/api.xml"));
System.out.println(xpath.valueOf(doc)); //nothing to print...
I test to remove xmlns="http://www.abc.com/" from XML file, it's be work!
how to change my java code to get Hello!, if xmlns="http://www.abc.com/" exist?
(I can't chagne this XML file)
thanks for help :)
You'll need to make the query aware of the xml namespace. This answer here looks like it will do the trick:
Default Xml Namespace JDOM and XPATH
You might also change your query to use local-name to ignore namespaces:
XPath xpath = XPath.newInstance("/*[local-name() = 'root']");
That should return the node named root. That is, if it supports it and I typed it correctly! :) I'm not familiar with java API's for XML + XPATH.
Be aware that xml namespaces exist to distinguish node 'root' from any other node named 'root'. Just like class/package namespaces. Ignoring them could lead to a name collision. Your milage may vary.
HTH,
Zach
I have not done this recently. But a quick search found
http://illegalargumentexception.blogspot.com/2009/05/java-using-xpath-with-namespaces-and.html
which point to the usage of a XPathFactory:
NamespaceContext context = new NamespaceContextMap("http://www.abc.com/" );
Or, you could use Zach's answer and just ignore the given namespace (if i understood him right). This could lead to problems if there are more 'root' nodes at the same hierarchy level..

Java+DOM: How do I elegantly rename an xmlns:xyz attribute?

I have something like that as input:
<root xmlns="urn:my:main"
xmlns:a="urn:my:a" xmlns:b="urn:my:b">
...
</root>
And want to have something like that as output:
<MY_main:root xmlns:MY_main="urn:my:main"
xmlns:MY_a="urn:my:a" xmlns:MY_b="urn:my:b">
...
</MY_main:root>
... or the other way round.
How do I achieve this using DOM in an elegant way?
That is, without searching for attribute names starting with "xmlns".
You will not find the xmlns attributes in your DOM, they are not part of the DOM.
You may have some success if you find the nodes you want (getElementsByTagNameNS) and set their qualifiedName (qname) to a new value containing the prefix you like. Then re-generate the XML document.
By the way, the namespace prefix (which is what you are trying to change) is largely irrelevant when using any sane XML parser. The namespace URI is what counts. Why would you want to set the prefix to a specific value?
I have used the following jdom stub to remove all the namespace references:
Element rootElement = new SAXBuilder().build(contents).getRootElement();
for (Iterator i = rootElement.getDescendants(new ElementFilter()); i.hasNext();) {
Element el = (Element) i.next();
if (el.getNamespace() != null) el.setNamespace(null);
}
return rootElement;
Reading and writing the xml is done as normal. If you are just after human readable output that should do the job. If however you need to convert back you may have a problem.
The following may work to replace the namespaces with a more friendly version based on your example (untested):
rootElement.setNamespace(Namespace.getNamespace("MY_Main", "urn:my:main"));
rootElement.addNamespaceDeclaration(Namespace.getNamespace("MY_a", "urn:my:a"))
rootElement.addNamespaceDeclaration(Namespace.getNamespace("MY_b", "urn:my:b"))

Categories