【问题标题】:Converting HTML to a Tree using Java使用 Java 将 HTML 转换为树
【发布时间】:2016-11-02 18:03:39
【问题描述】:

所以我正在尝试编写一个程序,该程序将包含简单 HTML 语法的文件放入树中,该树将显示标签的层次结构。最终,每个叶子都将包含一个标签(即 p、h、ul 等)和文本。其中大部分非常简单,我计划使用 Jtree 来显示最终输出。但是,我遇到的困难是通过语法并在不丢失关系的情况下使用标签构建初始树。我认为整个文件将是一个长字符串。该程序将找到一个“

希望你能得到我想要做的事情,不幸的是,我的尝试并不成功,因为它只显示了根标记的子节点。目前,我只是想让标签在树、文本和我以后无法弄清楚的东西中工作。为了测试代码,我使用了一个字符串"test",其中包含一些基本的示例 html 代码,创建 jtree 时每个节点都显示在根目录中,但 node2 中的子节点从不显示。我很困惑,无法解决这个问题。另外,有没有更简单/有效的方法来做到这一点?

**编辑:所以我修改了代码以使用 JSoup 工作。我设法让它工作,但是,我遇到了一个问题,由于某种原因,除了head 标签的第一个子标签之外的所有标签都被移到了body 下。所以现在body 有 3 个孩子而不是 1 个,head 只有 1 个而不是 3 个。另外,我将如何修改getChildren() 递归函数以适用于前一个子层中的每个子层?例如,要在title 标签中获取h3 标签?

package weboqltree_converter;

import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import java.util.ArrayList;
import java.awt.Dimension;
import java.util.List;
import javax.swing.tree.TreeNode;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Node;

public class GUI extends JFrame
{
    private JTree tree;
    private String test = "<html>"
            +   "<head>"
            +       "<title><h3>First parse<h3></title>"
            +       "<a></a>"
            +       "<h3></h3>"
            +   "</head>"
            +   "<body>"
            +       "<p>Parsed HTML into a doc.</p>"
            +   "</body>"
            + "</html>";

    private int parentNode;

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new GUI();
            }
        });
    }

    public GUI()
    {
        DefaultMutableTreeNode html = new DefaultMutableTreeNode("html");
        Document doc = Jsoup.parse(test);
        int children = doc.childNodes().get(0).childNodes().size();
        for(int i=0; i < children; i++){
            String tag = doc.childNodes().get(0).childNodes().get(i).nodeName();
            String text = "N/A"; //doc.childNodes().get(0).childNodes().get(i).toString();

            html.add(new DefaultMutableTreeNode("Tag: " + tag+ ", Text: " + text));

            System.out.println(tag+" : "+doc.childNodes().get(0).childNodes().get(i).childNodeSize());

            if(doc.childNodes().get(0).childNodes().get(i).childNodeSize() > 0){
                getChildren(html.getLastLeaf(), doc.childNodes().get(0).childNodes().get(i),0, doc.childNodes().get(0).childNodes().get(i).childNodeSize());
            }
        }
        System.out.println("tag: " + children);           


        //System.out.println(Tree.get(2) +" "+Tree.get(2).getChildCount());
        tree = new JTree(html);
        add(tree);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("JTree Example"); 
        this.setMinimumSize(new Dimension(300, 400));
        this.setExtendedState(3);
        this.pack();
        this.setVisible(true);
    }

    public void getChildren(DefaultMutableTreeNode tree, Node doc, int start, int size){

        tree.add(new DefaultMutableTreeNode("Tag: " + doc.childNodes().get(start).nodeName()));
        start++;

        if(start < size){
            getChildren(tree, doc, start, size);
        }

    }
}

【问题讨论】:

标签: java html arrays parsing tree


【解决方案1】:

您可以使用JSoup 来执行此操作。它读取一个字符串、一个文件或 URL 并将其解析为一个 Document 对象(它执行得非常快)。之后,您可以导航该对象并从中创建一个 JTree。

String html = "<html><head><title>First parse</title></head><body><p>Parsed HTML into a doc.</p></body></html>";
Document document = Jsoup.parse(html);

更新

我已更改您的代码以使用递归方法。因为文档中可能有多个根节点(通常是“document”-tag 和“html”-tag),所以添加一个默认根节点是个好主意。看看:

public GUI() {
    // create window
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setTitle("JTree Example");
    this.setMinimumSize(new Dimension(300, 400));
    this.setExtendedState(3);

    // create tree and root node
    this.tree = new JTree();
    final DefaultMutableTreeNode ROOT = new DefaultMutableTreeNode("Html Document");

    // create model
    DefaultTreeModel treeModel = new DefaultTreeModel(ROOT);
    tree.setModel(treeModel);

    // add scrolling tree to window
    this.add(new JScrollPane(tree));

    // parse document (can be cleaned too)
    Document doc = Jsoup.parse(test);
    // Cleaner cleaner = new Cleaner(Whitelist.simpleText());
    // doc = cleaner.clean(doc);

    // walk the document tree recursivly
    traverseRecursivly(doc.getAllElements().first(), ROOT);

    this.expandAllNodes(tree);
    this.pack();
    this.setLocationRelativeTo(null);
    this.setVisible(true);
}

private void traverseRecursivly(Node docNode, DefaultMutableTreeNode treeNode) {
    // iterate child nodes:
    for (Node nextChildDocNode : docNode.childNodes()) {
        // create leaf:
        DefaultMutableTreeNode nextChildTreeNode = new DefaultMutableTreeNode(nextChildDocNode.nodeName());
        // add child to tree:
        treeNode.add(nextChildTreeNode);
        // do the same for this child's child nodes:
        traverseRecursivly(nextChildDocNode, nextChildTreeNode);
    }
}

// can be removed ...
private void expandAllNodes(JTree tree) {
    int j = tree.getRowCount();
    int i = 0;
    while (i < j) {
        tree.expandRow(i);
        i += 1;
        j = tree.getRowCount();
    }
}

【讨论】:

  • 我之前从未使用过JSoup,一旦解析完成,如何在保持父子关系的同时将其添加到JTree?
  • 您更新的代码没有获得下一组子项(即标题的子项),此外,似乎所有子项标记都被添加到第二个父项;在这种情况下身体。我该如何解决?
  • title标签不能有子标签,其他p和h3元素不能出现在header中。您可能希望启用代码的更简洁部分以删除无效的 html。
【解决方案2】:

抱歉,这在很多层面上都是错误的。

首先,解析 html/xml 并不容易。而您当前获取它们的代码也太天真了。您最好尝试使用一些现有的库来为您完成解析工作,而不是自己做这样的事情。做到这一点对你来说已经够难的了。 (不过,您以正确稳健方式完成解析的机会接近于零)

那么:与其专注于“复杂”的任务……我更愿意建议您首先关注编程的一些工艺方面。例如:您的代码几乎无法测试(因为它在那个糟糕的构造函数方法中做所有事情)。它也比它应该的更难阅读。

我的(个人)推荐:

  1. 了解如何编写可测试代码(请参阅here
  2. 了解如何使用 TDD 和使用 JUnit 进行单元测试
  3. 阅读 Robert Martin 的这本书,了解“干净的代码”

换句话说:您似乎想把精力花在解决复杂问题上。但是为了以一种有效、持久的方式做到这一点……你缺乏非常基本的技能。当您编写解决某些问题的代码时,它并没有多大用处……当该代码质量不佳时! 我知道,这听起来不太“有趣”;但请相信我:以“正确的方式”进行 TDD 是一项非常有益的活动!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-08
    • 2014-08-30
    • 2023-03-03
    • 1970-01-01
    • 2016-08-24
    • 2013-10-29
    • 2021-03-31
    • 2013-01-05
    相关资源
    最近更新 更多