大家经常运用DOM4J操作XML文档,如果XML文档存在namespace的话,读写XML经常不工作,解决方案很简单的:
举个例子吧:
比如我一个XML文件头是这样的:
<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml"
version="1.0"
initialstate="coordinator">
请注意这个xml文件是带了namespace的,
读写这个xml要如下操作:
SAXReader reader = new SAXReader();
Map map = new HashMap();
map.put("scxml","http://www.w3.org/2005/07/scxml");
reader.getDocumentFactory().setXPathNamespaceURIs(map);
InputStream is = servletContext.getResourceAsStream("xxxx");
Document document = reader.read(is);
在操作任何节点的时候,你的XPath必须都要加上Namespace,以下都是可行的XPath表达式:
String strXPath = "//scxml:state[@id='member_init']";
String strXPath = "/scxml:*[name()='scxml']/scxml:*[name()='datamodel']/scxml:data/@name";
String strXPath = "/scxml:*[name()='scxml']/scxml:*[name()='state']/scxml:*[name()='state' and @id='member_init']/scxml:transition";
List list = document.selectNodes(strXPath);
看到没有,所有的//和/后面都要加上"scxml:"(节点属性前面不要加) .
第一个表达式是要找文档里面id为'member_init'的state节点
第二个表达式是找name属性,这个name属性的有这样的祖先链/scxml/datamodel/data
第三个也没什么了,跟找节点transition,并对它的祖先链有所要求
例如还要注意一下,你从Node api调用getPath()或者getUniquePath(),得到的XPath,是不带Namespace的,所以你要做如下处理:
public static final String XMLNS = "scxml";
String oriNodePath = node.getPath();
String xPath = null;
xPath = oriNodePath.replaceAll("/", "/"+XMLNS+":");
return xPath;
这样处理过的xPath才能被Document.select, Node.select函数处理
当然这里你也要小心的对属性元素区别处理,因为属性名前是不带namespace的.
举个例子吧:
比如我一个XML文件头是这样的:
<?xml version="1.0"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml"
version="1.0"
initialstate="coordinator">
请注意这个xml文件是带了namespace的,
读写这个xml要如下操作:
SAXReader reader = new SAXReader();
Map map = new HashMap();
map.put("scxml","http://www.w3.org/2005/07/scxml");
reader.getDocumentFactory().setXPathNamespaceURIs(map);
InputStream is = servletContext.getResourceAsStream("xxxx");
Document document = reader.read(is);
在操作任何节点的时候,你的XPath必须都要加上Namespace,以下都是可行的XPath表达式:
String strXPath = "//scxml:state[@id='member_init']";
String strXPath = "/scxml:*[name()='scxml']/scxml:*[name()='datamodel']/scxml:data/@name";
String strXPath = "/scxml:*[name()='scxml']/scxml:*[name()='state']/scxml:*[name()='state' and @id='member_init']/scxml:transition";
List list = document.selectNodes(strXPath);
看到没有,所有的//和/后面都要加上"scxml:"(节点属性前面不要加) .
第一个表达式是要找文档里面id为'member_init'的state节点
第二个表达式是找name属性,这个name属性的有这样的祖先链/scxml/datamodel/data
第三个也没什么了,跟找节点transition,并对它的祖先链有所要求
例如还要注意一下,你从Node api调用getPath()或者getUniquePath(),得到的XPath,是不带Namespace的,所以你要做如下处理:
public static final String XMLNS = "scxml";
String oriNodePath = node.getPath();
String xPath = null;
xPath = oriNodePath.replaceAll("/", "/"+XMLNS+":");
return xPath;
这样处理过的xPath才能被Document.select, Node.select函数处理
当然这里你也要小心的对属性元素区别处理,因为属性名前是不带namespace的.