XPath parser in Java

[list]
[*]1.概覽
[*]2.解決要點
[*]3.代碼實現
[*]4.測試代碼實現
[*]5.測試結果
[*]6.總結
[/list]

[b]1.概覽[/b]

本主題旨在不依賴第三方軟件情況下如何使用Java實現XPath的解析。

[b]2.解決要點[/b]

1)如何把XML文件/XML字符流轉換爲DOM模型下的Node/Element.

2)XML文件/XML字符流編碼格式的指定。

3)提供XML的Namespace Resolver.

4)調用XPath的相關API並依賴用戶指定的experssion進行解析,並返回結果。

[b]3.代碼實現[/b]


package com.chris.xpath;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;

import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* <code>XPathUtil</code>.
* @author chris.wang
*/
public class XPathUtil
{
private PrintStream error = System.err;

/**
* Populate XPath-expression.
* @param query
* @param xmlDocument
* @param defaultNamespaceContext
* @return value of element or attribute.
*/
public String evaluateXPath( String query, Node xmlDocument,
NamespaceContext defaultNamespaceContext )
{
String result = null;

XPathFactory factory = XPathFactory.newInstance();

XPath xpath = factory.newXPath();

xpath.setNamespaceContext(defaultNamespaceContext);

XPathExpression expr = null;

try
{
expr = xpath.compile(query);
}
catch ( XPathExpressionException xpee )
{
Throwable x = xpee;

if ( null != xpee.getCause() )
{
x = xpee.getCause();

if ( "javax.xml.transform.TransformerException".equals(x.getClass()
.getName()) )
{
error
.println("Error compiling xpath expression ["
+ query
+ "]. Could all the required namespaces be resolved from the previous response?");
}
else
{
error.println("Error compiling xpath expression [" + query
+ "]. Is the expression well-formed in XML Spy?");
}
}

x.printStackTrace(error);

return null;
}

try
{
result = (String) expr.evaluate(xmlDocument, XPathConstants.STRING);
}
catch ( XPathExpressionException e )
{
e.printStackTrace(error);
}

return result;
}

/**
* Convert xmlString into Node.
* @param xmlString
* @param encodingHint encoding type.
* @return Node
*/
public Node loadXMLResource( String xmlString, String encodingHint )
{
Node document = null;

if ( 0xFEFF == xmlString.charAt(0) )
{
xmlString = xmlString.substring(1);
}

InputSource source = new InputSource(new BufferedReader(new StringReader(
xmlString)));

if ( null != encodingHint )
{
source.setEncoding(encodingHint);
}

// parse the XML purely as well-formed XML and get a DOM tree
// represenation.
try
{
document = loadDocument(source);
}
catch ( SAXParseException spe )
{
// Error generated by the parser
if ( null != spe.getSystemId() )
{
error.println("\n** XML Parsing error **, line "
+ spe.getLineNumber() + " character " + spe.getColumnNumber()
+ ", uri=" + spe.getSystemId());
error.println(" " + spe.getMessage() + "\n"); // NOPMD
}
else
{
error.println("\n** XML Parsing error ** : " + spe.getMessage()
+ "\n");
}

// Use the contained exception, if any
Exception x = spe;

if ( null != spe.getException() )
{
x = spe.getException();
}

x.printStackTrace(error);
}
catch ( SAXException se )
{
document = null;

error
.println("Error parsing the XML resource - is the XML valid and well-formed?");

// Use the contained exception, if any
Exception x = se;

if ( null != se.getException() )
{
x = se.getException();
}

x.printStackTrace(error);
}
catch ( IOException ioe )
{
document = null;

error
.println("Error loading the XML resource - can the xmlString be read?");

ioe.printStackTrace(error);
}

return document;
}

/**
* Load document from InputSource( i.e. XML file or other stream ).
* @param source
* @return Node of DOM.
* @throws SAXException
* @throws IOException
*/
public Node loadDocument( InputSource source ) throws SAXException,
IOException
{
Node document = null;

// Get a parser capable of parsing XML into a DOM tree
DocumentBuilder parser = null;

// Create the dom factory
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();

domFactory.setNamespaceAware(true);
domFactory.setValidating(false); // only for DocType (dtd) validation

try
{
parser = domFactory.newDocumentBuilder();
}
catch ( ParserConfigurationException pce )
{
pce.printStackTrace(error);
}

// parse the XML purely as well-formed XML and get a DOM tree
// represenation.
parser.reset();

document = parser.parse(source);

return document;
}

}


[b]4.測試代碼的實現[/b]


package com.chris.xpath;

import java.util.Iterator;
import java.util.Map;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;

import org.w3c.dom.Node;

public class XPathUtilDriver
{

private static NamespaceContext defaultNamespaceContext;
static
{
defaultNamespaceContext = new NamespaceContext()
{

private Map<String, String> m_prefixMap = null; // NOPMD

public String getNamespaceURI( String prefix )
{
if ( null == prefix )
{
throw new NullPointerException("Null prefix"); // NOPMD
}
else
{
if ( "xml".equals(prefix) )
{
return XMLConstants.XML_NS_URI;
}

if ( null != m_prefixMap )
{
for ( String key : m_prefixMap.keySet() )
{
if ( key.equals(prefix) )
{
return m_prefixMap.get(key);
}
}
}
}

return XMLConstants.NULL_NS_URI;
}

// This method isn't necessary for XPath processing.
public String getPrefix( String uri )
{
throw new UnsupportedOperationException();
}

// This method isn't necessary for XPath processing either.
public Iterator getPrefixes( String uri )
{
throw new UnsupportedOperationException();
}

};
}

public static void main( String[] args )
{
String xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<books><book><name>JUnit in Action</name>" + "</book>"
+ "</books>";
XPathUtil util = new XPathUtil();
Node node = util.loadXMLResource(xmlString, "utf-8");
String value = util.evaluateXPath("//books/book[1]/name/text()", node,
defaultNamespaceContext);
System.out.println("execute result" + value);
}
}


[b]5.測試結果[/b]

[code]
execute result:JUnit in Action
[/code]

[b]6.總結[/b]

1)如果要是namespace產生效果一定要加上domFactory.setNamespaceAware(true), 不然解析後的Node可能不能用.
2)XML可能涉及到不同的編碼,所以編碼問題也是一個注意點。
3)第三方開發軟件如JDOM,DOM4j對XPath都有很好的支持,個人覺得使用也是很方便,如果你的項目中剛好用的這個組件,那一些解析的操作就可以省了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章