7/9/08


Java and XML: query over XML

There is not included API for XQuery in Java 5 or 6. There is not included XPath API in Java till 5. But in java 5 and higher there is facilities for addressing element or group of elements via XPath. Probably in Java 7 it will be realized (XQJ or JSR 225 - like JDBC). Any case SUN is not only vendor of such kind of API.

XPath with Saxon
SAXON is the XSLT and XQuery Processor. Most XSLT and XQuery functionality in Saxon will work without installing JAXP 1.3.

import net.sf.saxon.dom.DOMNodeList;
import net.sf.saxon.om.NamespaceConstant;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.xpath.XPathEvaluator;
import org.xml.sax.InputSource;
import javax.xml.namespace.NamespaceContext;
import javax.xml.transform.sax.SAXSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.FileInputStream;
import java.util.Iterator;
import net.sf.saxon.dom.ElementOverNodeInfo;

public class XPathExample implements NamespaceContext {

 public static void main (String args[]) throws Exception {
  System.setProperty("javax.xml.xpath.XPathFactory:"+NamespaceConstant.OBJECT_MODEL_SAXON, "net.sf.saxon.xpath.XPathFactoryImpl");
  XPathFactory xpf = XPathFactory.newInstance(NamespaceConstant.OBJECT_MODEL_SAXON);
  XPath xpe = xpf.newXPath();
  InputSource is = new InputSource(new FileInputStream("D:/dev/Temp_java/src/com/PhoneBook.xml"));
  SAXSource ss = new SAXSource(is);
  NodeInfo doc = ((XPathEvaluator)xpe).setSource(ss);
  XPathExpression findLine = xpe.compile("/*[1]/*[1]");
  DOMNodeList matchedLines = (DOMNodeList)findLine.evaluate(doc, XPathConstants.NODESET) ;
  if (matchedLines != null) {
   for (int i = 0; i < matchedLines.getLength(); i++) {
    ElementOverNodeInfo info =((ElementOverNodeInfo)matchedLines.item(i));
    System.out.println(info.getTextContent());
   }
  }
 }

 public String getNamespaceURI(String prefix) {
  return null;
 }
 public String getPrefix(String namespaceURI) {
  return null;
 }
 public Iterator getPrefixes(String namespaceURI) {
  return null;
 }
}

Result:

0
Alex
Kuiv, Kominterna 28
aillusions@gmail.com
+380664392825


XPath with JAXP 1.3
JAXP is the Java API for XML Processing. In version SE 1.5 it included by default but there is version JAXP 1.3 for JDK 1.4 (by default has JAXP 1.1). To use this API in 1.4 property -Djava.endorsed.dirs=DIR_WITH_JAXP1.3_JARS should be set, or copy all of the jar files except jaxp-api.jar into /jre/lib/endorsed.

import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Iterator;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class XPathDemo {

 public static void main(String[] args) throws Exception {

  String xmlFile = "D:/dev/Temp_java/src/com/PhoneBook.xml";
  String xpathExpression = "/*/pb:BookRecord/pb:id";

  XPathFactory xpf = XPathFactory.newInstance();
  XPath xpath = xpf.newXPath();

  NamespaceContextImpl namespaceContextImpl = new NamespaceContextImpl();
  namespaceContextImpl.bindPrefixToNamespaceURI("pb","http://www.epam.com/com/PhoneBook");

  xpath.setNamespaceContext(namespaceContextImpl);
  FileInputStream saxStream = new FileInputStream(xmlFile);
  NodeList saxNodeList = null;
  saxNodeList = (NodeList)xpath.evaluate(xpathExpression, new InputSource(saxStream), XPathConstants.NODESET);

  for (int i = 0; i < saxNodeList.getLength(); i++) {
   System.out.println(" name: " + saxNodeList.item(i).getNodeName()+", value: " + saxNodeList.item(i).getNodeValue());
  }
 }
}

class NamespaceContextImpl implements NamespaceContext {

 private HashMap prefixToNamespaceURI = new HashMap();
 private HashMap namespaceURIToPrefix = new HashMap();

 public void bindPrefixToNamespaceURI(String prefix, String namespaceURI) {
  prefixToNamespaceURI.put(prefix, namespaceURI);
  namespaceURIToPrefix.put(namespaceURI, prefix);
 }

 public String getNamespaceURI(String prefix) {
  if (prefixToNamespaceURI.containsKey(prefix))
   return (String)prefixToNamespaceURI.get(prefix);
  return XMLConstants.NULL_NS_URI;
 }

 public String getPrefix(String namespaceURI) {
  if (namespaceURIToPrefix.containsKey(namespaceURI))
   return (String)namespaceURIToPrefix.get(namespaceURI);
  return null;
 }

 public Iterator getPrefixes(String namespaceURI) {
  throw new UnsupportedOperationException("NamespaceContextImpl#getPrefixes(String namespaceURI) not implemented");
 }
}

And result:

name: pb:id, value: null
name: pb:id, value: null
name: pb:id, value: null


XPath with Jaxen
Jaxen is able to interact with DOM, Dom4j and JDOM.

import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.jaxen.dom.DOMXPath;
import org.jaxen.XPath;
import java.util.List;
import java.util.Iterator;

public class Main {

 public static void main(String argv[]) throws Exception {
  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  factory.setNamespaceAware(true);

  Document doc = factory.newDocumentBuilder().parse("D:/dev/Temp_java/src/com/PhoneBook.xml");
  XPath xpath = new DOMXPath("//pb:id");
  xpath.addNamespace("pb", "http://www.epam.com/com/PhoneBook");
  xpath.addNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");

  List results = xpath.selectNodes(doc);
  Iterator resultIter = results.iterator();

  while(resultIter.hasNext()){
   System.out.println( resultIter.next());
  }
 }
}

As result:

<pb:id>0</pb:id>
<pb:id>1</pb:id>
<pb:id>2</pb:id>


XPath with SAXPath
SAXPath has been merged into the Jaxen codebase and is no longer being maintained separately.

XPath with Xalan
Xalan-Java is an XSLT processor for transforming XML documents: http://xml.apache.org/xalan-j. Xalan includes the JAXP packages, implements the TrAX portion of that API (javax.xml.transform....), implements the XPath API of JAXP (javax.xml.xpath....), and includes xercesImpl.jar from Xerces-Java 2.9.0, which implements the parser portion of the API (javax.xml.parser....).

import java.io.FileInputStream;
import java.io.OutputStreamWriter;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.xpath.XPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.InputSource;

public class ApplyXPath {

 public static void main(String[] args) throws Exception {

  String filename = "D:/dev/Temp_java/src/com/PhoneBook.xml";
  String xpath = "/*[1]/*[1]";

  InputSource in = new InputSource(new FileInputStream(filename));
  DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
  dfactory.setNamespaceAware(true);
  Document doc = dfactory.newDocumentBuilder().parse(in);
  Transformer serializer = TransformerFactory.newInstance().newTransformer();
  serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

  NodeIterator nl = XPathAPI.selectNodeIterator(doc, xpath);

  Node n;
  while ((n = nl.nextNode()) != null) {
   serializer.transform(new DOMSource(n), new StreamResult(new OutputStreamWriter(System.out)));
  }
 }
}

Result:

<pb:BookRecord xmlns:pb="http://www.epam.com/com/PhoneBook" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <pb:id>0</pb:id>
  <pb:name>Alex</pb:name>
  <pb:address>Kuiv, Kominterna 28</pb:address>
  <pb:email>aillusions@gmail.com</pb:email>
  <pb:phone>+380664392825</pb:phone>
 </pb:BookRecord>

No comments: