【问题标题】:parsing HTML file to DOM Tree for extract (Java)将 HTML 文件解析为 DOM 树以进行提取(Java)
【发布时间】:2012-12-04 17:47:49
【问题描述】:

所以我试图将 HTML 文件解析到 DOM 树中并通过 XPath 表达式提取节点。

我可以成功地将 HTML 解析到 DOM 树中,但是当我尝试通过 XPath 提取节点时,我什么也得不到。

注意这只是一个代码sn-p用于相关性。

import org.cyberneko.html.parsers.DOMParser;
import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.DOMReader;
import org.xml.sax.InputSource;

DOMParser parser = new DOMParser();

parser.parse(new InputSource("file:///Z:/homepage.htm"));
org.w3c.dom.Document doc = parser.getDocument();

DOMReader reader = new DOMReader();
Document document = reader.read(doc);

@SuppressWarnings("unchecked")
List<Node> nodes = document.selectNodes("//HEAD/LINK");

节点 = 0。

为了完整起见,这里是 HTML 的 sn-p:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<HTML xmlns="http://www.w3.org/1999/xhtml">
    <HEAD>
        <META content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
        <TITLE/>
        <LINK
            href="wcm/groups/visual/documents/webasset/####_ie_5_css.css"
            media="all" rel="stylesheet" type="text/css"/>
        <LINK
            href="wcm/groups/visual/documents/webasset/####_ie_5_5000_css.css"
            media="all" rel="stylesheet" type="text/css"/>
        <LINK
            href="wcm/groups/visual/documents/webasset/####_ie_6_css.css"
            media="all" rel="stylesheet" type="text/css"/>

非常感谢一如既往,

【问题讨论】:

  • 为了进一步清晰,我添加了导入。

标签: java html dom xpath


【解决方案1】:

@BrianAgnew 是对的,您的问题与命名空间有关。

问题出在这里

<HTML xmlns="http://www.w3.org/1999/xhtml">

由于文档具有默认命名空间 xmlns="http://www.w3.org/1999/xhtml",因此您的 XPath 表达式 //HEAD/LINK 将不起作用,因为 HEADLINK 元素都属于默认命名空间 (xmlns="http://www.w3. org/1999/xhtml")

@BrianAgnew 建议使用:

document.selectNodes("//*[local-name()='HEAD']/*[local-name()='LINK']");

有关local-name() 为何有效的更多信息,请参阅

XPATHS and Default Namespacesanswer 在同一个线程上

还有另一种无需使用 local-name() 即可选择这些节点的方法,即为默认命名空间创建一个别名,然后在 XPath 表达式中使用它:

例如

    Map<String, String> namespaceUris = new HashMap<String, String>();  
    namespaceUris.put("foobar", "http://www.w3.org/1999/xhtml");  

    XPath xPath = DocumentHelper.createXPath("//foobar:HEAD/foobar:LINK");  
    xPath.setNamespaceURIs(namespaceUris);  

    @SuppressWarnings("unchecked")
    List<Nodes> selectNodes = xPath.selectNodes(document);

上面我们将别名 foobar 设置为与默认命名空间相同的 URI (http://www.w3.org/1999/xhtml)。这允许使用 xpath 表达式,例如

//foobar:HEAD/foobar:LINK 工作,当然你可以使用任何你喜欢的别名。

这是一个使用这两种方法的示例应用程序,它有点粗糙,但应该给你正确的想法

package org.foo.bar.foobar;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import nu.xom.Nodes;

import org.cyberneko.html.parsers.DOMParser;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.io.DOMReader;
import org.dom4j.io.XMLWriter;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class App 
{
    public static void main( String[] args ) throws SAXException, IOException
    {

        DOMParser parser = new DOMParser();

        parser.parse(new InputSource("file:///Z:/homepage.htm"));
        org.w3c.dom.Document doc = parser.getDocument();

        DOMReader reader = new DOMReader();
        Document document = reader.read(doc);

        XMLWriter xmlWriter = new XMLWriter(System.out);
        xmlWriter.write(document);

        @SuppressWarnings("unchecked")

        List<Node> nodes = document.selectNodes("//*[local-name()='HEAD']/*[local-name()='LINK']");
        System.out.println("Number of Nodes: " +nodes.size());

        Map<String, String> namespaceUris = new HashMap<String, String>();  
        namespaceUris.put("foobar", "http://www.w3.org/1999/xhtml");  

        XPath xPath = DocumentHelper.createXPath("//foobar:HEAD/foobar:LINK");  
        xPath.setNamespaceURIs(namespaceUris);  

        @SuppressWarnings("unchecked")
        List<Nodes> selectNodes = xPath.selectNodes(document);
        System.out.println("Number of nodes: " +selectNodes.size());

    }
}

这是我用来衡量的 pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.foo.bar</groupId>
    <artifactId>foobar</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>foobar</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
            <version>1.9.6.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

另请参阅One Fork, How To use Dom4J XPath with XML Namespaces,它涵盖了与您遇到的情况非常相似的情况

【讨论】:

  • 我已经修改了你的答案,我在下面更正了我的答案
【解决方案2】:

我怀疑这与命名空间有关。

document.selectNodes("//HEAD/LINK");

应该是命名空间感知的。例如

document.selectNodes("//*[local-name()='HEAD']/*[local-name()='LINK']");

XPath 2.0 将允许

document.selectNodes("//:HEAD/:LINK");

【讨论】:

  • 我正在使用 NekoHTML,推荐使用我查看过的某些线程中的 NekoHTML :(
  • 啊。适当修改了我的答案
  • 嗨,所以当我尝试这样做时,我得到了无效的表达。
  • +1 表达式几乎是正确的, //*[local-name()='HEAD']/*[local-name()='LINK'],而不是 //*[local -name()='HEAD']/:*[local-name()='LINK'] (选择链接元素时有一个不必要的冒号
猜你喜欢
  • 2010-11-28
  • 2015-11-03
  • 2013-02-06
  • 2010-10-02
  • 2016-03-20
  • 2019-07-26
  • 2016-01-18
  • 2014-01-15
  • 1970-01-01
相关资源
最近更新 更多