谁有双世宠妃百度网盘小说百度网盘txt

如何用好Xpath以精确定位节点位置 - 开源中国社区
当前访客身份:游客 [
当前位置:
最近使用MetaSeeker抓取新浪微博,可最近新浪微博的格式结构发生了些变化。
对于一条含有转发内容的微博,该微博的发布时间和转发内容的发布时间都位于class名为lf的节点中,我在MetaStudio中设置的抓取规则抓取页面时,当遇到有转发内容的微博,获取每条微博的发布时间将会错误地抓取转发内容的发布时间。它们Xpath表达式不同,如图所示:
因此我想利用Xpath来区别两个class名同为lf的节点,想请教大家Xpath表达式该怎么编写!
共有0个答案
更多开发者职位上
有什么技术问题吗?
司徒春运的其它问题
类似的话题JDOM2.0.5版本通过xpath读取xml或读取带有命名空间的xml
JDOM2.0.5版本通过xpath读取xml或读取带有命名空间的xml
org.jdom2.xpath.XPath类居然标注过时,无奈之下只能研究api。
发现Use XPathFactory/XPathExpression/XPathBuilder
也就是说jdom应该是将xpath类的功能进行了更加详细的分类。
根据经验进行了一些类的测试,最后得出了读取xml的两种方式。
第一种方式,通过XPathFactory类读取xml
xml文件的内容如下
[html] &span&style="font-size:14px"&&?xml&version="1.0"?&&&&?xml-stylesheet&type="text/xsl"&href="test.xsl"?&&&&homepages&xmlns:xlink="http://www.w3.org/1999/xlink"&&&&&&&&homepage&xlink:type="simple"&&&&xlink:href=".cn"&Visit&W3School&/homepage&&&&&&&&&&homepage&xlink:type="simple"&&&&xlink:href="http://www.w3.org"&Visit&W3C&/homepage&&&&&&&&/homepages&&/span&&&
通过SAXBuilder获取document和root
[java] String&path&=&System.getProperty("user.dir")&+&"\\src\\com\\xml\\file\\test.xml";&&&&&&&&&&&&SAXBuilder&saxBuilder&=&new&SAXBuilder();&&&&&&&&&&&&Document&document&=&saxBuilder.build(path);&&&&&&&&&&&&Element&root&=&document.getRootElement();&&
建立XPathFactory类的对象,需要引入jaxen的jar包,我们使用JaxenXPathFactory类来生成XPathFactory
[java] XPathFactory&factory&=&JaxenXPathFactory.instance();&&
生产xpath表达式实例对象,并获取结果集
[java] XPathExpression&Object&&objs&=&pile("//homepages");&&&&&&&&&&&&List&Object&&objList&=&objs.diagnose(root,&false).getResult();&&
完整代码是
[java] String&path&=&System.getProperty("user.dir")&+&"\\src\\com\\xml\\file\\test.xml";&&&&&&&&&&&&SAXBuilder&saxBuilder&=&new&SAXBuilder();&&&&&&&&&&&&Document&document&=&saxBuilder.build(path);&&&&&&&&&&&&Element&root&=&document.getRootElement();&&&&&&&&&&&&XPathFactory&factory&=&JaxenXPathFactory.instance();&&&&&&&&&&&&XPathExpression&Object&&objs&=&pile("//homepages");&&&&&&&&&&&&List&Object&&objList&=&objs.diagnose(root,&false).getResult();&&
第二种方式,通过XPathBuilder获取xpath表达式的实例对象集合
首先来创建一个filter,org.jdom2.filter.Filters中提供给我们了一些过滤器,我们这里选择元素类型的,Filter接口的全名是org.jdom2.filter.Filter
[java] Filter&Element&&filter&=&Filters.element();&&
生成XPathBuilder对象
[java] XPathBuilder&Element&&builder&=&new&XPathBuilder&Element&("//homepages",&filter);&&
根据它的compileWith(XPathFactory factory)方法来获取到我们需要的xpath表达式的实例对象集合
[java] XPathFactory&factory&=&JaxenXPathFactory.instance();&&&&&&&&&&&&XPathExpression&Element&&objs&=&pileWith(factory);&&
之后的方式就和方法1一样了。
完整代码是
[java] String&path&=&System.getProperty("user.dir")&+&"\\src\\com\\xml\\file\\test.xml";&&&&&&&&&&&&SAXBuilder&saxBuilder&=&new&SAXBuilder();&&&&&&&&&&&&Document&document&=&saxBuilder.build(path);&&&&&&&&&&&&Element&root&=&document.getRootElement();&&&&&&&&&&&&Filter&Element&&filter&=&Filters.element();&&&&&&&&&&&&XPathBuilder&Element&&builder&=&new&XPathBuilder&Element&("//homepages",&filter);&&&&&&&&&&&&XPathFactory&factory&=&JaxenXPathFactory.instance();&&&&&&&&&&&&XPathExpression&Element&&objs&=&pileWith(factory);&&&&&&&&&&&&List&Element&&objList&=&objs.diagnose(root,&false).getResult();&&&&&
获取带有命名空间的xml文件内容
使用XPathBuilder的setNamespace方法声明命名空间,Xpath表达式不需要再写"//",例如
[java] XPathBuilder&Element&&builder&=&new&XPathBuilder&Element&("ci:Teacher",&filter);&&&&&&&&&&&&builder.setNamespace("ci",&"/tuple");&&
发表评论:
TA的最新馆藏如何对一个用xpath获得xml片段再用xpath进行查询? - ITeye问答
一个网页或xml我想用xpath获取其中的内容,网上的教程都是一步到位地抓到。我希望能用一个xpath语句先抓一个大块,再用另一个xpath抓大块里面的小块。
比如下面的html:我希望先用\\table抓到整个table的部分,再从这个结果中用\\tr抓到所有的tr。两者我都要。怎么做?
&div&...&/div&
&td&...&/td&
&td&...&/td&
&td&...&/td&
&td&...&/td&
&td&...&/td&
&td&...&/td&
解析xml字符串一般用jsoup
已解决问题
未解决问题JAXP和Dom4j通过XPath获取带命名空间的节点 -
- ITeye技术网站
博客分类:
一、JAXP对XPath的支持
XPath是从JAXP1.3开始被支持的,在这些API中,其核心接口有XPath和XPathExpression,它们都在javax.xml.xpath包中,分别表示XPath对象以及被预编译后的表达式对象。
例如,对于如下的示例文件(schema_test_copy.xml)
&?xml version="1.0" encoding="UTF-8"?&
&bean name="user" class="com.daniele.appdemo.test.domain.User"&&/bean&
&bean name="company" class="com.daniele.appdemo.pany"&&/bean&
&description date=""&This is a XML Schema example.&/description&
&/templet&
我们可以利用上述两个和XPath相关的接口进行一系列的节点访问操作。
public static void main(String[] args) throws XPathExpressionException, IOException {
// 返回默认的DOM对象模型的XPath工厂
XPathFactory factory = XPathFactory.newInstance();
XPath xPath = factory.newXPath();
// 获取templet下name属性值为user的bean元素的class属性
String expression = "/templet/bean[@name='user']/@class";
InputSource source = new InputSource();
source.setByteStream(new FileInputStream(new File("resource/xml/schema/schema_test_copy.xml")));
// 预编译表达式,这种方式对于对同一个表达式多次求值来说,可提高运行效率,并且是线程安全的
XPathExpression compiledExpression = pile(expression);
System.out.println(compiledExpression.evaluate(source));
上述代码执行后将会正确的得到schema_test_copy.xml文件中第一个bean元素的class的属性值。
现在,把xml文档的内容做如下修改(schema_test.xml):
&templet xmlns="http://www./schema/templet"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www./schema/templet ../../../schema/schame_test.xsd"&
&bean name="user" class="com.daniele.appdemo.test.domain.User"&&/bean&
&bean name="company" class="com.daniele.appdemo.pany"&&/bean&
&description date=""&This is a XML Schema example.&/description&
&/templet&
注意对比文件中根节点的变化,它在schema_test_copy.xml的基础上增加了两个与命名空间相关的属性xmlns和xmlns:xsi,其中xmlns是我们自定义文档结构规范的命名空间,是使用XPath时需要考虑的重点。
此时我们再次运行上面的main()方法后会发现将得不到任何输出结果。这主要是由于XPath不支持默认命名空间造成的,因此我们需要将前缀和相关的URI关联起来。
为达到这个目的,JAVA为我们提供了一个javax.xml.namespace.NamespaceContext接口,它的目的在于让我们可以在XPath接口对象中设置这个context,当XPath进行编译时,会根据前缀和URI的映射关系来匹配实际的节点。
NamespaceContext接口定义有如下三个方法:
1)public String getNamespaceURI(String prefix):获取绑定到当前范围中前缀的命名空间 URI;
2)public String getPrefix(String namespaceURI):获取绑定到当前范围命名空间 URI的前缀;
3)public Iterato getPrefixes(String namespaceURI):获取绑定到当前范围命名空间 URI的所有前缀。
下面来自定义实现一个NamespaceContext:
package com.daniele.appdemo.xml.jaxp.
import java.util.ArrayL
import java.util.HashM
import java.util.I
import java.util.L
import java.util.M
import java.util.S
import javax.xml.XMLC
import javax.xml.namespace.NamespaceC
* &p&默认的命名空间处理器&/p&
&a href="mailto:"&Daniele&/a&
* @version 1.0.0,
AppDemo1.0.0
public class DefaultNamespaceContext implements NamespaceContext {
/** 维持前缀与命名空间URI的映射关系(K:前缀,V:命名空间URI) */
private Map&String,String& namespaceMap = new HashMap&String,String&();
public DefaultNamespaceContext() {
addNamespace("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
public void addNamespace(String prefix, String namespaceURI) {
namespaceMap.put(prefix, namespaceURI);
* &p&获取绑定到当前范围中前缀的命名空间 URI。&/p&
* @author &a href="mailto:"&Daniele&/a&
* @param prefix
* @since AppDemo1.0.0
public String getNamespaceURI(String prefix) {
String namespaceURI = namespaceMap.get(prefix);
return namespaceURI != null ? namespaceURI : XMLConstants.NULL_NS_URI;
* &p&获取绑定到当前范围命名空间 URI的前缀。&/p&
* @author &a href="mailto:"&Daniele&/a&
* @param namespaceURI
* @since AppDemo1.0.0
public String getPrefix(String namespaceURI) {
Set&String& keySet = namespaceMap.keySet();
for (String key : keySet) {
if (namespaceMap.get(key).equals(namespaceURI))
return XMLConstants.DEFAULT_NS_PREFIX;
* &p&获取绑定到当前范围命名空间 URI的所有前缀。&/p&
* @author &a href="mailto:"&Daniele&/a&
* @param namespaceURI
* @since AppDemo1.0.0
public Iterator&?& getPrefixes(String namespaceURI) {
List&String& prefixes = new ArrayList&String&();
Set&String& keySet = namespaceMap.keySet();
for (String key : keySet) {
if (namespaceMap.get(key).equals(namespaceURI))
prefixes.add(key);
return prefixes.iterator();
完成后利用这个实现类,将前面的main()方法做如下修改(注意第5,11,12,15行的代码):
public static void main(String[] args) throws IOException, XPathExpressionException {
XPathFactory factory = XPathFactory.newInstance();
XPath xPath = factory.newXPath();
DefaultNamespaceContext defaultNamespaceContext = new DefaultNamespaceContext();
设置前缀与命名空间URI的映射关系
XPath表达式中使用的前缀与文档中实际的前缀并没有关联,这里只是为了在XPath中增加一个前缀标识所有。
但前缀对应的命名空间URI必须与文档中实际的命名空间URI保持一致
defaultNamespaceContext.addNamespace("t", "http://www./schema/templet");
xPath.setNamespaceContext(defaultNamespaceContext);
InputSource source = new InputSource(new FileInputStream(new File("resource/xml/schema/schema_test.xml")));
String expression = "/t:templet/t:bean[@name='user']/@class";
XPathExpression compiledExpression = pile(expression);
System.out.println(compiledExpression.evaluate(source));
再次运行main()方法将重新得到前面相同的运行结果。
二、Dom4j对XPath的支持
除了JAXP外,JDOM和Dom4j也提供了对XPath的支持。其中在Dom4j中,与JAXP的XPathExpression作用类似的接口为org.dom4j.XPath,这是在dom4j-1.x.x.jar中,因此在实际的使用过程中需将此包加入到classpath中。
例如,利用XPath获取上述schema_test_copy.xml中无命名空间的节点:
package com.daniele.appdemo.xml.dom4j;
import java.io.F
import org.dom4j.D
import org.dom4j.DocumentE
import org.dom4j.DocumentF
import org.dom4j.DocumentH
import org.dom4j.E
import org.dom4j.N
import org.dom4j.XP
import org.dom4j.io.SAXR
* &p&Dom4j对XPath支持的测试类&/p&
&a href="mailto:"&Daniele&/a&
* @version 1.0.0,
AppDemo1.0.0
public class Dom4jXPathTester {
public static void main(String[] args) throws DocumentException {
DocumentFactory factory = DocumentFactory.getInstance();
SAXReader reader = new SAXReader(factory);
// 解析无命名空间的XML文档
Document document = reader.read(new File("./resource/xml/schema/schema_test_copy.xml"));
Element root = document.getRootElement();
String subNodeName = "bean";
* 从工厂(DocumentFactory)对象或DocumentHelper中创建XPath对象,
* 与JAXP的XPathExpression类似,XPath的作用在于避免对同一个XPath求值时进行重复编译的问题
XPath rootSubNodePath = factory.createXPath(root.getPath() + "/" + subNodeName);
System.out.println("根元素" + root.getName() + "内共有"
+ rootSubNodePath.selectNodes(document).size() + "个"
+ subNodeName + "子节点");
subNodeName = "description";
rootSubNodePath = DocumentHelper.createXPath(root.getPath() + "/" + subNodeName);
Node subNode = rootSubNodePath.selectSingleNode(document);
System.out.println("根元素" + root.getName() + "子节点"
+ subNode.getName() + "的文本值为:" + subNode.getText());
运行后将得到如下结果:
根元素templet内共有2个bean子节点
根元素templet子节点description的文本值为:This is a XML Schema example.
与JAXP的情况一样,如果上述代码用来获取schema_test.xml文件中带命名空间的节点,则同样不会得到预期结果。为此,Dom4j也提供了与JAXP类似的解决方案,实际使用情况甚至比JAXP的还要方便和灵活。
Dom4j也提供了一个名为NamespaceContext的接口(与javax.xml.namespace.NamespaceContext没有任何关系),它可以根据某一个前缀来得到对应的URI,它在Dom4j的依赖包jaxen-1.x.jar中,因此在使用时需要将此包导入到classpath中。
jaxen提供了一个NamespaceContext的默认实现类SimpleNamespaceContext。在这个实现类中有一个叫namespaces的Map成员属性,它是用来维护命名空间前缀和URI的映射关系的。当进行XPath求值时,首先会将表达式中的前缀标识提取出来,再根据这个标识,到它所关联的NamespaceContext的映射中获取对应的URI,最终再调用NamespaceContext接口方法translateNamespacePrefixToUri(String prefix)返回URI。
对于SimpleNamespaceContext来说,它有如下两种方式来添加命名空间关系:
1)利用构造函数来添加——public SimpleNamespaceContext(Map namespaces), 这种方式传入一个已经在外部设置好了的映射关系即可;
2)调用SimpleNamespaceContext实例的addNamespace(String prefix, String URI)方法来逐条添加。
完成后,再调用XPath实例的setNamespaceContext(namespaceContext)方法,将Context实例传入即可。例如:
package com.daniele.appdemo.xml.dom4j;
import java.io.F
import java.util.HashM
import java.util.M
import org.dom4j.D
import org.dom4j.DocumentE
import org.dom4j.DocumentF
import org.dom4j.DocumentH
import org.dom4j.XP
import org.dom4j.io.SAXR
import org.jaxen.NamespaceC
import org.jaxen.SimpleNamespaceC
* &p&Dom4j利用XPath获取具有命名空间的节点的测试类&/p&
&a href="mailto:"&Daniele&/a&
* @version 1.0.0,
AppDemo1.0.0
public class Dom4jNamespaceXPathTester {
public static void main(String[] args) throws DocumentException {
DocumentFactory factory = DocumentFactory.getInstance();
SAXReader reader = new SAXReader(factory);
// 解析具有命名空间的XML文档
Document document = reader.read(new File("./resource/xml/schema/schema_test.xml"));
// 命名空间前缀与URI的映射
Map&String, String& namespaceMap = new HashMap&String, String&();
namespaceMap.put("t", "http://www./schema/templet");
XPath xPath =
// 根据映射关系构建NamespaceContext实例
NamespaceContext namespaceContext = new SimpleNamespaceContext(namespaceMap);
xPath = DocumentHelper.createXPath("/t:templet/t:bean");
xPath.setNamespaceContext(namespaceContext);
System.out.println(xPath.selectNodes(document).size());
xPath = factory.createXPath("/t:templet/t:bean");
xPath.setNamespaceContext(namespaceContext);
System.out.println(xPath.selectNodes(document).size());
对于XPath的实例来说,可以完成摒弃对NamespaceContext实例的创建和设置,可以调用它的另外一个方法setNamespaceURIs( map),直接将映射关系传递给这个方法就可以了。例如:
// 命名空间前缀与URI的映射
Map&String, String& namespaceMap = new HashMap&String, String&();
namespaceMap.put("t", "http://www./schema/templet");
XPath xPath =
xPath = DocumentHelper.createXPath("/t:templet/t:bean");
xPath.setNamespaceURIs(namespaceMap);
System.out.println(xPath.selectNodes(document).size());
xPath = factory.createXPath("/t:templet/t:bean");
xPath.setNamespaceURIs(namespaceMap);
System.out.println(xPath.selectNodes(document).size());
在setNamespaceURIs()方法的内部,它会创建一个SimpleNamespaceContext来维护映射关系(具体实现在org.dom4j.xpath.DefaultXPath中)。
对于上述两种方式,都有一个比较明显的缺陷,即对于每一个新建的XPath实例来说,在求值之前都需要设置一次context或映射关系,这是比较繁琐的。
为此,Dom4j也提供了一个类似JAXP那样的全局设置方式,即调用DocumentFactory实例的setXPathNamespaceURIs(Map map)方法。
public static void main(String[] args) throws DocumentException {
DocumentFactory factory = DocumentFactory.getInstance();
SAXReader reader = new SAXReader(factory);
// 解析具有命名空间的XML文档
Document document = reader.read(new File("./resource/xml/schema/schema_test.xml"));
// 命名空间前缀与URI的映射
Map&String, String& namespaceMap = new HashMap&String, String&();
namespaceMap.put("t", "http://www./schema/templet");
// 设置全局的映射关系
factory.setXPathNamespaceURIs(namespaceMap);
XPath xPath =
xPath = DocumentHelper.createXPath("/t:templet/t:bean");
System.out.println(xPath.selectNodes(document).size());
xPath = factory.createXPath("/t:templet/t:bean");
System.out.println(xPath.selectNodes(document).size());
回顾第一部分中最后一块代码片段,JAXP的javax.xml.xpath.XPath并不代表某一个具体的表达式对象(Dom4j中的XPath更像是javax.xml.xpath.XPathExpression),因此在javax.xml.xpath.XPath实例中设置的NamespaceContext就表示为全局的,即后续所有与编译好了的XPathExpression(对于Dom4j来说是XPath)都使用同一个全局的NamespaceContext来将表达式中的前缀标识替换成对应的URI。
浏览: 14683 次
来自: 成都
写的非常详细。挺。

我要回帖

更多关于 双世宠妃网盘资源链接 的文章

 

随机推荐