I want to query an XML via XPath. This XML has a namespace declared. I 've read that a NameContext on the XPath object has to be set and namespace awareness in the document factory should be enabled.
But the output in the getNamespaceURI(#String) method is never print. What I'm doing wrong?
String xpathStr = ... //some string
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
Document document = builder.parse(settlementFile);
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath(),
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
System.out.println("I'm here");
... //do some work
}
public String getPrefix(String uri) {
throw new UnsupportedOperationException();
}
public Iterator getPrefixes(String uri) {
throw new UnsupportedOperationException();
}
});
XPathExpression xpathExpression = xpath.compile(xpathStr);
String result = xpathExpression.evaluate(document);
Related
I want to fetch value of the node ServerVersion
<result>
<response id="27mSTG">
<routing>
<configs>
<linqmap.routing.RoutingServerConfig>
<SERVER_VERSION>1.0.388</SERVER_VERSION>
<PRE_PROCESSING_FILE_LOCATION/>
I have tried:
#Override
public void getProp(String prop) {
try {
final Document document = loadXMLFromString();
document.getElementById(??);
} catch (Exception e) {
e.printStackTrace();
}
}
private Document loadXMLFromString() throws Exception
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(xmlString));
return builder.parse(is);
}
But I’m not sure how to get the node’s ID.
Is there any easier way? Maybe even string parsing is enough?
There is no attribute Id defined in your xml element SERVER_VERSION. You can use document.getElementByTagName("SERVER_VERSION") to get the value.
Or use XPath to read the node:
final Document document = loadXMLFromString();
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
String xpathExpr="/result/SERVER_VERSION"; // assume result is the root node.
Node node=(Node)xPath.compile(xpathExpr).evaluate(document, XPathConstants.NODE);
I have an xml file like this:
<?xml version="1.0" encoding="UTF-8"?>
<ClOrdIDS><ClOrdID id="1"><Account>1005390</Account><Symbol>SAP</Symbol><SecurityID>4663789</SecurityID><SecurityExchange>XETR</SecurityExchange><Price>23.0</Price><Order_Type>Limit</Order_Type><Side>SELL</Side><Order_Quantity>0.001</Order_Quantity></ClOrdID><ClOrdID id="2"><Account>1005390</Account><Symbol>SAP</Symbol><SecurityID>4663789</SecurityID><SecurityExchange>XETR</SecurityExchange><Price>13.0</Price><Order_Type>Limit</Order_Type><Side>SELL</Side><Order_Quantity>0.001</Order_Quantity></ClOrdID><ClOrdID id="3"><Account>1005390</Account><Symbol>SAP</Symbol><SecurityID>4663789</SecurityID><SecurityExchange>XETR</SecurityExchange><Price>13.0</Price><Order_Type>Limit</Order_Type><Side>BUY</Side><Order_Quantity>0.001</Order_Quantity></ClOrdID><ClOrdID id="4"><Account>1005390</Account><Symbol>SAP</Symbol><SecurityID>4663789</SecurityID><SecurityExchange>XETR</SecurityExchange><Price>13.0</Price><Order_Type>Limit</Order_Type><Side>BUY</Side><Order_Quantity>0.001</Order_Quantity></ClOrdID><ClOrdID id="5"><Account>1005390</Account><Symbol>SAP</Symbol><SecurityID>4663789</SecurityID><SecurityExchange>XETR</SecurityExchange><Price>13.0</Price><Order_Type>Limit</Order_Type><Side>BUY</Side><Order_Quantity>0.001</Order_Quantity></ClOrdID><ClOrdID id="6"><Account>1005390</Account><Symbol>SAP</Symbol><SecurityID>4663789</SecurityID><SecurityExchange>XETR</SecurityExchange><Price>13.0</Price><Order_Type>Limit</Order_Type><Side>BUY</Side><Order_Quantity>0.001</Order_Quantity></ClOrdID><ClOrdID id="7"><Account>1005390</Account><Symbol>SAP</Symbol><SecurityID>4663789</SecurityID><SecurityExchange>XETR</SecurityExchange><Price>13.0</Price><Order_Type>Limit</Order_Type><Side>SELL</Side><Order_Quantity>0.001</Order_Quantity></ClOrdID></ClOrdIDS>
How can I extract the elements of child with ClOrdID id="3" ?
THANKS
You could do it this way
String xmlString = ...
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(xmlString);
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
String xpathExp = "/ClOrdIDS/ClOrdID[#id=\"3\"]";
NodeList childNodeList = (NodeList) xpath.evaluate(xpathExp, doc, XPathConstants.NODESET);
Since the tags on the question are JDOM, not DOM, you could use JDOM instead ;-) :
Document doc = new SaxBuilder().build(xmlFile);
XPathExpression<Element> xpe = XPathFactory.instance()
.compile("/ClOrdIDS/ClOrdID[#id=\"3\"]", Filters.element());
List<Element> idThrees = xpe.evaluate(doc);
Here is the code to do it in VTD-XML...
import com.ximpleware.*;
public class removeElement {
public static void main(String s[]) throws VTDException{
VTDGen vg = new VTDGen();
if (!vg.parseFile("input.xml", false))
return;
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("/ClOrdIDS/ClOrdID[#id='3']");
int i=0;
while((i=ap.evalXPath())!=-1){
}
}
}
My xml String is
Got message from Queue ==> <?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003
/05/soap-envelope"><soapenv:Body><ns1:PostPublicationResponse xmlns:ns1="http://www.openoandm.org/xml/ISBM/"><ns1:Messag
eID>urn:uuid:7d361fb0-bc54-48bd-bbd1-6e34960ef3f8</ns1:MessageID><ns1:MessageContent><MessageContent xmlns="http://www.o
penoandm.org/xml/ISBM/"><hi>k786</hi></MessageContent></ns1:MessageContent></ns1:PostPublicationResponse></soapenv:Body>
</soapenv:Envelope>
Now i have writtent a function that is trying to get Content of element MessageContent i.e <hi>k786</hi> but i am getting null value always.
My function to parse above xml is:
private String parseQueueMessage(String message)
throws ParserConfigurationException, SAXException, IOException,
XPathExpressionException {
String resultMsg = "";
DocumentBuilderFactory domFactory = DocumentBuilderFactory
.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new java.io.StringReader(
message)));
XPath xpath = XPathFactory.newInstance().newXPath();
// XPath Query for showing all nodes value
xpath.setNamespaceContext(new NamespaceContext() {
#SuppressWarnings("rawtypes")
#Override
public Iterator getPrefixes(String arg0) {
return null;
}
#Override
public String getPrefix(String arg0) {
return null;
}
#Override
public String getNamespaceURI(String arg0) {
if("xmlns:ns1".equals(arg0)) {
return "http://www.openoandm.org/xml/ISBM/";
}
return null;
}
});
XPathExpression expr = xpath.compile("//xmlns:ns1:MessageContent");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println("The message obtained after parsing : "
+ nodes.item(i).getNodeValue());
resultMsg = nodes.item(i).getNodeValue();
}
return resultMsg;
}
What i have done wrong in here?
Thanks in advance
You need to define the name space URI first before selecting from XPATH. For example, first define the namespace URI as follows on the root;
element.setAttribute("xmlns:ns1", "http://www.openoandm.org/xml/ISBM/");
xpath.compile("//ns1:MessageContent");
//Try something like ...
XmlDocument doc = new XmlDocument();
doc.LoadXml("urn:uuid:7d361fb0-bc54-48bd-bbd1-6e34960ef3f8k786
");
XmlElement elem = (XmlElement) doc.DocumentElement.FirstChild;
Console.Write("{0}:{1} = {2}", elem.Prefix, elem.LocalName, elem.InnerText);
Console.WriteLine("\t namespaceURI=" + elem.NamespaceURI);
this is my XML file :
<sitemesh>
<mapping path="/editor/tempPage/**" exclude="true"/>
<mapping decorator="/WEB-INF/views/decorators/detailstheme.jsp"
path="/*" exclude="false" />
</sitemesh>
I want list of mapping node with their attribute values.
this should be done using Xpath.
my xpath expression is :
expr = xpath.compile("/sitemesh/mapping");
but i am getting null in nodelist.
this is my code:
Map<String,String> map=new HashMap<String, String>();
// reading xml file
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
Document doc = null;
XPathExpression expr = null;
try {
builder = factory.newDocumentBuilder();
// creating input stream
doc = builder.parse(file);
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
expr = xpath.compile("//mapping");
} catch (Exception e) {
LOG.error("some exception message", e);
}
//------------------------------------------------------------------------
NodeList attributeElements = null;
try {
attributeElements =(NodeList)expr.evaluate(doc, XPathConstants.NODE);
} catch (XPathExpressionException e) {
LOG.error("some exception message", e);
}
System.out.println("lenght:"+attributeElements.getLength());
for (int i = 0; i < attributeElements.getLength(); i++) {
Node node=attributeElements.item(i);
System.out.println("node:"+node.getNodeValue());
NamedNodeMap attrs = node.getAttributes();
for(i = 0 ; i<attrs.getLength() ; i++) {
Attr attribute = (Attr)attrs.item(i);
System.out.println("Node Attributes : " + attribute.getName()+" = "+attribute.getValue());
}
}
//-------------------------------------------------------------------------
// writing xml file
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer;
try {
transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(file);// creating output
// stream
transformer.transform(source, result);
} catch (Exception e) {
LOG.error("some exception message", e);
}
return map;
i am getting null for attributeElements
i want to show values of path,decorator and exclude on JSP page.But i am unable to get list of node through xpath expression.
I want solution for reading mapping node element in Xpath.
[edit] /sitemesh/mapping also works .
The issue here is that you evaluating the express for XPathConstants.NODE while the nodeList maps to XPathConstants.NODESET. please refer below link.
http://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/xpath/XPathConstants.html#NODESET
Added sample code for illustration purpose only:
public void testXpathExpr(){
String testXML = "<sitemesh><mapping path=\"/editor/tempPage/**\" exclude=\"true\"/><mapping decorator=\"/WEB-INF/views/decorators/detailstheme.jsp\" path=\"/*\" exclude=\"false\" /></sitemesh>";
NodeList nodeList = getNodeList(testXML);
}
private NodeList getNodeList(String xml) throws SAXException, IOException, ParserConfigurationException, XPathExpressionException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = docFactory.newDocumentBuilder();
document = builder.parse(new ByteArrayInputStream( xml.getBytes() ) );
XPathExpression exprPath = xpath.compile(xpathExpr);
NodeList nodeList = (NodeList) exprPath.evaluate(document, XPathConstants.NODESET);;
return nodeList;
}
Hope this helps!
Your xpath works perfectly for me. Below is the sample code:
public class Parser {
public static void main(String[] args) throws Exception, Exception {
final DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
final Document doc = builder.parse("src/sitemesh.xml");
final XPathFactory xPathfactory = XPathFactory.newInstance();
final XPath xpath = xPathfactory.newXPath();
final XPathExpression expr = xpath.compile("/sitemesh/mapping");
Object node = expr.evaluate(doc, XPathConstants.NODE);
System.out.println(node);
}
}
sitemesh.xml contains your sample input.
I have xml like below (Google API), but can't get gphoto:id element value. How to do that ? Notice: When i'm using domFactory.setNamespaceAware(true);, /feed/entry xpath stops working.
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:gphoto="http://schemas.google.com/photos/2007"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">
<entry>
<title type="text">Test</title>
<author>
<name>username</name>
<uri>https://picasaweb.google.com/113422203255202384532</uri>
</author>
<gphoto:id>57060151229174417</gphoto:id>
</entry>
</feed>
Java
NodeList nodes = (NodeList) path(body, "/feed/entry", XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
Node n = nodes.item(i);
XPath xpath = XPathFactory.newInstance().newXPath();
// empty :(
System.out.println(
xpath.evaluate("id[namespace-uri()='http://schemas.google.com/photos/2007']",n)
);
// empty too :(
System.out.println(
xpath.evaluate("gphoto:id",n)
);
// ok
System.out.println(
xpath.evaluate("author",n)
);
l.add(new Album("", "", ""));
}
path method
private Object path(String content, String path, QName returnType) {
try {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(content)));
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile(path);
return expr.evaluate(doc, returnType);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
SOLVED according to #gioele answer path() method is now like below:
private Object path(String content, String path, QName returnType) {
try {
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(content)));
XPath xpath = XPathFactory.newInstance().newXPath();
NamespaceContext nsContext = new NamespaceContext() {
#Override
public Iterator getPrefixes(String namespaceURI) {
return null;
}
#Override
public String getPrefix(String namespaceURI) {
return null;
}
#Override
public String getNamespaceURI(String prefix) {
if ("gphoto".equals(prefix))
return "http://schemas.google.com/photos/2007";
if ("media".equals(prefix))
return "http://search.yahoo.com/mrss/";
if("".equals(prefix))
return "http://www.w3.org/2005/Atom";
throw new IllegalArgumentException(prefix);
}
};
xpath.setNamespaceContext(nsContext);
XPathExpression expr = xpath.compile(path);
return expr.evaluate(doc, returnType);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Before compiling your xpath you need to register a NamespaceContext.
Have a look at the code in https://github.com/gioele/xpathapi-jaxp/blob/master/src/main/java/it/svario/xpathapi/jaxp/NodeNamespaceContext.java.
If you want to avoid all these complications, you can use the XPathAPI library:
Map<String, String> nsMap = new HashMap<String, String>();
nsMap.put(XMLConstants.DEFAULT_NS_PREFIX, "http://www.w3.org/2005/Atom");
nsMap.put("gphoto", "http://schemas.google.com/photos/2007");
List<Node> entries = XPathAPI.selectListOfNodes(doc, "/feed/entry", nsMap);
for (Node entry : entries) {
String id = XPathAPI.selectSingleNodeAsString(entry, "gphoto:id", nsMap);
// or, if you prefer a Node
// Node id = XPathAPI.selectSingleNode(entry, "gphoto:id", nsMap);
}
Disclaimer: I am the creator of XPathAPI-JAXP.
A much easier way to deal with the namespace issue is just to redirect the call from the NamespaceContext to the document lookupNamespaceURI() method. This will return "http://search.yahoo.com/mrss/" when called with "media" etc...
xPath.setNamespaceContext(new NamespaceContext() {
#Override
public String getNamespaceURI(String prefix) {
return doc.lookupNamespaceURI(prefix);
}
#Override
public Iterator<?> getPrefixes(String arg0) {
return null;
}
#Override
public String getPrefix(String arg0) {
return null;
}
});