如何在Android上将JavaXPath与KML文件和名称空间一起使用
我正在努力研究如何在包含新的gx:Track和gx:coord标记的KML文件上使用XPath。问题在于如何在Android下使用XPath和名称空间 我看了很多例子,包括如何在Android上将JavaXPath与KML文件和名称空间一起使用,java,android,xpath,xml-namespaces,Java,Android,Xpath,Xml Namespaces,我正在努力研究如何在包含新的gx:Track和gx:coord标记的KML文件上使用XPath。问题在于如何在Android下使用XPath和名称空间 我看了很多例子,包括 但我似乎连这些例子都不起作用 以下代码和输出说明了我的问题: public App() { super(); try { test( testDoc1() ); test( testDoc2() ); } catch( Exception e ) {
public App() {
super();
try {
test( testDoc1() );
test( testDoc2() );
} catch( Exception e ) {
e.printStackTrace();
} finally {
Log.d( "TEST-FINISHED", "test is finished" );
}
}
private String toXmlString( Document document ) throws TransformerException {
DOMSource domSource = new DOMSource( document );
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult( writer );
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform( domSource, result );
return writer.toString();
}
private Document testDoc1() throws ParserConfigurationException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware( true );
Document mDocument = documentBuilderFactory.newDocumentBuilder().newDocument();
String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
Element mKmlElement = mDocument.createElement( "kml" );
mKmlElement.setAttributeNS( XMLNS_NAMESPACE_URI, "xmlns", "http://www.opengis.net/kml/2.2" );
mKmlElement.setAttributeNS( XMLNS_NAMESPACE_URI, "xmlns:gx", "http://www.google.com/kml/ext/2.2" );
mDocument.appendChild( mKmlElement );
Element mPlacemarkElement = mDocument.createElement( "Placemark" );
mKmlElement.appendChild( mPlacemarkElement );
Element gxTrackElement = mDocument.createElement( "gx:Track" );
mPlacemarkElement.appendChild( gxTrackElement );
Element gxCoordElement = mDocument.createElement( "gx:coord" );
gxCoordElement.setTextContent( "-122.207881 37.371915 156.000000" );
gxTrackElement.appendChild( gxCoordElement );
return mDocument;
}
private Document testDoc2() throws ParserConfigurationException, IOException, SAXException {
String kmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark><gx:Track><gx:coord>-122.207881 37.371915 156.000000</gx:coord></gx:Track></Placemark></kml>";
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware( true );
Document mDocument = documentBuilderFactory.newDocumentBuilder().parse( new InputSource( new StringReader( kmlString ) ) );
return mDocument;
}
private void test( Document mDocument ) throws Exception {
String xml = toXmlString( mDocument );
Log.d( "TEST-XML", xml );
XPath xPath = XPathFactory.newInstance().newXPath();
xPath.setNamespaceContext( new NamespaceContext() {
@Override
public String getNamespaceURI( String prefix ) {
switch( prefix ) {
case XMLConstants.DEFAULT_NS_PREFIX:
return "http://www.opengis.net/kml/2.2";
case "gx":
return "http://www.google.com/kml/ext/2.2";
}
return XMLConstants.NULL_NS_URI;
}
@Override
public String getPrefix( String namespaceURI ) {
return null;
}
@Override
public Iterator getPrefixes( String namespaceURI ) {
return null;
}
} );
NodeList result1 = (NodeList) xPath.evaluate( "/kml", mDocument, XPathConstants.NODESET );
Log.d( "TEST-RESULT1", String.valueOf( result1.getLength() ) );
NodeList result2 = (NodeList) xPath.evaluate( "/kml/Placemark", mDocument, XPathConstants.NODESET );
Log.d( "TEST-RESULT2", String.valueOf( result2.getLength() ) );
NodeList result3 = (NodeList) xPath.evaluate( "/kml/Placemark/gx:Track", mDocument, XPathConstants.NODESET );
Log.d( "TEST-RESULT3", String.valueOf( result3.getLength() ) );
}
以下是文件2的结果:
2018-11-17 17:51:28.348 22837-22837/ca.csdesigninc.offroadtracker D/TEST-XML: <?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2"><Placemark><gx:Track><gx:coord>-122.207881 37.371915 156.000000</gx:coord></gx:Track></Placemark></kml>
2018-11-17 17:51:28.358 22837-22837/ca.csdesigninc.offroadtracker D/TEST-RESULT1: 0
2018-11-17 17:51:28.363 22837-22837/ca.csdesigninc.offroadtracker D/TEST-RESULT2: 0
2018-11-17 17:51:28.372 22837-22837/ca.csdesigninc.offroadtracker D/TEST-RESULT3: 0
包括在文件2中。如果我删除它,前2个XPath测试的结果是正确的(对于这两个文档),事实上XPath测试3现在可以在文档2上运行。不幸的是,我仍然无法控制这种行为
我可能遗漏了一些明显的东西,希望您能提供帮助。这些差异是由于名称空间造成的。无论是XML的生成方式,还是在XPath中选择内容的时间 不幸的是,很难看出区别,因为碰巧由
testDoc1()
的toXmlString()
序列化的XML与内存中文档的状态不完全匹配
当您使用createElement()
构造kml
元素时,它会创建一个绑定到“无命名空间”的元素。然后,添加了名称空间属性,当使用toXmlString()
进行序列化时,这些属性会出现,并使kml
元素出现在http://www.opengis.net/kml/2.2
名称空间
如果要将该XML封送回新的文档
对象,则kml
元素将绑定到该名称空间。但是,该元素的当前内存中对象不是
您可以通过添加一些附加诊断信息println
来观察这一点:
NodeList result1 = (NodeList) xPath.evaluate("/kml", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result1.getLength()));
System.out.println("Namespace URI: " + result1.item(0).getNamespaceURI());
System.out.println("Prefix: " + result1.item(0).getPrefix());
您可以对XML进行往返,并观察到在整理序列化的XML时,它的行为有所不同:
private void test(Document mDocument) throws Exception {
String xml = toXmlString(mDocument);
System.out.println( xml);
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
mDocument = documentBuilderFactory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
然而,这是欺骗。您真正想要做的是首先确保正确创建元素。创建要绑定到命名空间的元素时,请使用createElementNS()
方法,如JavaDoc注释中所示:
要创建具有限定名称和命名空间URI的元素,请使用createElementNS
方法
因此,要创建绑定到http://www.opengis.net/kml/2.2
命名空间,您可能希望使用:
Element mKmlElement = mDocument.createElementNS("http://www.opengis.net/kml/2.2", "kml");
以及:
对于gx:Track
元素也是如此:
Element gxTrackElement = mDocument.createElementNS("http://www.google.com/kml/ext/2.2","gx:Track");
一旦让文档对象真正相等和正确,就需要调整XPath
对于XPath,如果不应用名称空间前缀,它将选择绑定到“无名称空间”的元素。因此,/kml
将只选择未绑定到命名空间的kml
元素。但是由于kml
元素绑定到http://www.opengis.net/kml/2.2
namespace,它不会选择它们
在重写getNamespaceURI()
函数时,可以为Google KML扩展名称空间保留gx
,然后将任何其他名称空间前缀默认解析为http://www.opengis.net/kml/2.2
:
@Override
public String getNamespaceURI(String prefix) {
return "gx".equals(prefix) ? "http://www.google.com/kml/ext/2.2" : "http://www.opengis.net/kml/2.2";
}
然后,调整XPath语句,为这些KML元素使用前缀。如果您使用上述代码,那么您使用的前缀并不重要。除gx以外的任何内容都将返回http://www.opengis.net/kml/2.2
名称空间
NodeList result1 = (NodeList) xPath.evaluate("/k:kml", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result1.getLength()));
System.out.println("Namespace URI: " + result1.item(0).getNamespaceURI());
System.out.println("Prefix: " + result1.item(0).getPrefix());
NodeList result2 = (NodeList) xPath.evaluate("/k:kml/k:Placemark", mDocument, XPathConstants.NODESET);
System.out.println( String.valueOf(result2.getLength()));
NodeList result3 = (NodeList) xPath.evaluate("/k:kml/k:Placemark/gx:Track", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result3.getLength()));
总而言之:
public App() {
super();
try {
test( testDoc1() );
test( testDoc2() );
} catch( Exception e ) {
e.printStackTrace();
} finally {
Log.d( "TEST-FINISHED", "test is finished" );
}
}
private String toXmlString(Document document) throws TransformerException {
DOMSource domSource = new DOMSource(document);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
return writer.toString();
}
private Document testDoc1() throws ParserConfigurationException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document mDocument = documentBuilderFactory.newDocumentBuilder().newDocument();
String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
//Element mKmlElement = mDocument.createElement("kml");
Element mKmlElement = mDocument.createElementNS("http://www.opengis.net/kml/2.2", "kml");
//mKmlElement.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns", "http://www.opengis.net/kml/2.2");
mKmlElement.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns:gx", "http://www.google.com/kml/ext/2.2");
mDocument.appendChild(mKmlElement);
//Element mPlacemarkElement = mDocument.createElement("Placemark");
Element mPlacemarkElement = mDocument.createElementNS("http://www.opengis.net/kml/2.2", "Placemark");
//mPlacemarkElement.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns", "http://www.opengis.net/kml/2.2");
mKmlElement.appendChild(mPlacemarkElement);
//Element gxTrackElement = mDocument.createElement("gx:Track");
Element gxTrackElement = mDocument.createElementNS("http://www.google.com/kml/ext/2.2","gx:Track");
mPlacemarkElement.appendChild(gxTrackElement);
//Element gxCoordElement = mDocument.createElement("gx:coord");
Element gxCoordElement = mDocument.createElementNS("http://www.google.com/kml/ext/2.2", "gx:coord");
gxCoordElement.setTextContent("-122.207881 37.371915 156.000000");
gxTrackElement.appendChild(gxCoordElement);
return mDocument;
}
private Document testDoc2() throws ParserConfigurationException, IOException, SAXException {
String kmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark><gx:Track><gx:coord>-122.207881 37.371915 156.000000</gx:coord></gx:Track></Placemark></kml>";
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document mDocument = documentBuilderFactory.newDocumentBuilder().parse(new
InputSource(new StringReader(kmlString)));
return mDocument;
}
private void test(Document mDocument) throws Exception {
String xml = toXmlString(mDocument);
System.out.println( xml);
XPath xPath = XPathFactory.newInstance().newXPath();
xPath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
return "gx".equals(prefix) ? "http://www.google.com/kml/ext/2.2" : "http://www.opengis.net/kml/2.2";
}
@Override
public String getPrefix(String namespaceURI) {
if ("http://www.google.com/kml/ext/2.2".equals(namespaceURI)) {
return "gx";
}
return null;
}
@Override
public Iterator getPrefixes(String namespaceURI) {
List<String> ns = new ArrayList<>();
ns.add("gx");
return ns.iterator();
}
});
NodeList result1 = (NodeList) xPath.evaluate("/k:kml", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result1.getLength()));
System.out.println("Namespace URI: " + result1.item(0).getNamespaceURI());
System.out.println("Prefix: " + result1.item(0).getPrefix());
NodeList result2 = (NodeList) xPath.evaluate("/k:kml/k:Placemark", mDocument, XPathConstants.NODESET);
System.out.println( String.valueOf(result2.getLength()));
NodeList result3 = (NodeList) xPath.evaluate("/k:kml/k:Placemark/gx:Track", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result3.getLength()));
}
public应用程序(){
超级();
试一试{
test(testDoc1());
测试(testDoc2());
}捕获(例外e){
e、 printStackTrace();
}最后{
Log.d(“测试完成”、“测试完成”);
}
}
私有字符串toXmlString(文档文档)引发TransformerException{
DOMSource DOMSource=新的DOMSource(文档);
StringWriter编写器=新的StringWriter();
StreamResult结果=新的StreamResult(writer);
TransformerFactory tf=TransformerFactory.newInstance();
变压器=tf.新变压器();
transformer.transform(domSource,result);
返回writer.toString();
}
私有文档testDoc1()引发ParserConfiguration异常{
DocumentBuilderFactory DocumentBuilderFactory=DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document mDocument=documentBuilderFactory.newDocumentBuilder().newDocument();
字符串XMLNS_名称空间_URI=”http://www.w3.org/2000/xmlns/";
//元素mKmlElement=mDocument.createElement(“kml”);
元素mKmlElement=mDocument.createElements(“http://www.opengis.net/kml/2.2“,“kml”);
//setAttributeNS(XMLNS_名称空间_URI,“XMLNS”,“http://www.opengis.net/kml/2.2");
setAttributeNS(XMLNS_名称空间_URI,“XMLNS:gx,”http://www.google.com/kml/ext/2.2");
mDocument.appendChild(mKmlElement);
//Element-mPlacemarkElement=mDocument.createElement(“Placemark”);
Element-mPlacemarkElement=mDocument.createElements(“http://www.opengis.net/kml/2.2“,”地标“);
//setAttributeNS(XMLNS_名称空间_URI,“XMLNS”,“http://www.opengis.net/kml/2.2");
appendChild(mPlacemarkElement);
//元素gxTrackElement=mDocument.createElement(“gx:Track”);
元素gxTrackElement=mDocument.createElements(“http://www.google.com/kml/ext/2.2“,“gx:轨道”);
appendChild(gxTrackElement);
//元素gxCoordElement=mDocument.createElement(“gx:coord”);
元素gxCoordElement=mDocument.createElements(“http://www.google.com/kml/ext/2.2“,“gx:coord”);
gxCoordElement.setTextContent(“-122.207881 37.371915 156.000000”);
追加子元素(gxCoordElement);
返回mDocument;
}
私有文档testDoc2()抛出ParserConfiguration异常、IOException、SAXException{
字符串kmlString=“-122.207881 37.371915 156.000000”;
DocumentBuilderFactory documentBuilderFactor
@Override
public String getNamespaceURI(String prefix) {
return "gx".equals(prefix) ? "http://www.google.com/kml/ext/2.2" : "http://www.opengis.net/kml/2.2";
}
NodeList result1 = (NodeList) xPath.evaluate("/k:kml", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result1.getLength()));
System.out.println("Namespace URI: " + result1.item(0).getNamespaceURI());
System.out.println("Prefix: " + result1.item(0).getPrefix());
NodeList result2 = (NodeList) xPath.evaluate("/k:kml/k:Placemark", mDocument, XPathConstants.NODESET);
System.out.println( String.valueOf(result2.getLength()));
NodeList result3 = (NodeList) xPath.evaluate("/k:kml/k:Placemark/gx:Track", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result3.getLength()));
public App() {
super();
try {
test( testDoc1() );
test( testDoc2() );
} catch( Exception e ) {
e.printStackTrace();
} finally {
Log.d( "TEST-FINISHED", "test is finished" );
}
}
private String toXmlString(Document document) throws TransformerException {
DOMSource domSource = new DOMSource(document);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
return writer.toString();
}
private Document testDoc1() throws ParserConfigurationException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document mDocument = documentBuilderFactory.newDocumentBuilder().newDocument();
String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
//Element mKmlElement = mDocument.createElement("kml");
Element mKmlElement = mDocument.createElementNS("http://www.opengis.net/kml/2.2", "kml");
//mKmlElement.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns", "http://www.opengis.net/kml/2.2");
mKmlElement.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns:gx", "http://www.google.com/kml/ext/2.2");
mDocument.appendChild(mKmlElement);
//Element mPlacemarkElement = mDocument.createElement("Placemark");
Element mPlacemarkElement = mDocument.createElementNS("http://www.opengis.net/kml/2.2", "Placemark");
//mPlacemarkElement.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns", "http://www.opengis.net/kml/2.2");
mKmlElement.appendChild(mPlacemarkElement);
//Element gxTrackElement = mDocument.createElement("gx:Track");
Element gxTrackElement = mDocument.createElementNS("http://www.google.com/kml/ext/2.2","gx:Track");
mPlacemarkElement.appendChild(gxTrackElement);
//Element gxCoordElement = mDocument.createElement("gx:coord");
Element gxCoordElement = mDocument.createElementNS("http://www.google.com/kml/ext/2.2", "gx:coord");
gxCoordElement.setTextContent("-122.207881 37.371915 156.000000");
gxTrackElement.appendChild(gxCoordElement);
return mDocument;
}
private Document testDoc2() throws ParserConfigurationException, IOException, SAXException {
String kmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark><gx:Track><gx:coord>-122.207881 37.371915 156.000000</gx:coord></gx:Track></Placemark></kml>";
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document mDocument = documentBuilderFactory.newDocumentBuilder().parse(new
InputSource(new StringReader(kmlString)));
return mDocument;
}
private void test(Document mDocument) throws Exception {
String xml = toXmlString(mDocument);
System.out.println( xml);
XPath xPath = XPathFactory.newInstance().newXPath();
xPath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
return "gx".equals(prefix) ? "http://www.google.com/kml/ext/2.2" : "http://www.opengis.net/kml/2.2";
}
@Override
public String getPrefix(String namespaceURI) {
if ("http://www.google.com/kml/ext/2.2".equals(namespaceURI)) {
return "gx";
}
return null;
}
@Override
public Iterator getPrefixes(String namespaceURI) {
List<String> ns = new ArrayList<>();
ns.add("gx");
return ns.iterator();
}
});
NodeList result1 = (NodeList) xPath.evaluate("/k:kml", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result1.getLength()));
System.out.println("Namespace URI: " + result1.item(0).getNamespaceURI());
System.out.println("Prefix: " + result1.item(0).getPrefix());
NodeList result2 = (NodeList) xPath.evaluate("/k:kml/k:Placemark", mDocument, XPathConstants.NODESET);
System.out.println( String.valueOf(result2.getLength()));
NodeList result3 = (NodeList) xPath.evaluate("/k:kml/k:Placemark/gx:Track", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result3.getLength()));
}