java - Java中使用SAX解析器同时读取父级和子级

标签 java xml sax

我有一个非常小的 xml 文件,我只想用 Java 读取它。引用this post后,我决定使用 SAX 解析器。我的 xml 文件如下所示-

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
    <library name="Central Library">
        <read>
            <book id="001" lang="ENG" title="Operating System Concepts" author="Silberschatz" />
            <book id="002" lang="ENG" title="Design Patterns: Elements of Reusable Object-Oriented Software" author="Gangs of Four" />
        </read>
        <unread>
            <book id="003" lang="ENG" title="Introduction to Algorithms" author="Cormen" />
            <book id="004" lang="ENG" title="Computer networks" author="Tanenbaum" />
        </unread>
    </library>
</catalog>

在阅读此 xml 时,我无法识别已读和未读的书籍。 下面是解析器代码-

import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class ParseXML extends DefaultHandler {
    private Library lib;
    public ParseXML(String file) throws ParserConfigurationException, SAXException, IOException {
        parse(file);
    }
    private void parse(String file) throws ParserConfigurationException, SAXException, IOException {
        final SAXParserFactory factory = SAXParserFactory.newInstance();
        final SAXParser parser = factory.newSAXParser();
        parser.parse(file, this);
    }
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if (qName.equals("library")) {
            String name = attributes.getValue("name");
            lib = new Library(name);
        }
        if (qName.equals("book")) {
            String id = attributes.getValue("id");
            String lang = attributes.getValue("lang");
            String title = attributes.getValue("title");
            String author = attributes.getValue("author");

            Book book = new Book(id, lang, title, author);

            // How to decide here, to which list this book should be added
            lib.addIntoReadBooks(book);
            // lib.addIntoUnreadBooks(book);
        }
    }

    /**
    * @return the library
    */
    public Library getLibrary() {
        return lib;
    }
    public static void main(String[] args) {
        try {
            ParseXML parseXML = new ParseXML("repository/books.xml");
            Library library = parseXML.getLibrary();

            System.out.println("Library=" + library);

            } catch (ParserConfigurationException e) {
            System.err.println("Error " + e.getMessage());
            } catch (SAXException e) {
            System.err.println("Error " + e.getMessage());
            } catch (IOException e) {
            System.err.println("Error " + e.getMessage());
        }
    }
}

图书馆和书籍类如下-

库.java

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public final class Library {
    private final String name;
    private final List<Book> readBooks;
    private final List<Book> unreadBooks;

    public Library(String name) {
        this.name = name;
        readBooks = new ArrayList<Book>();
        unreadBooks = new ArrayList<Book>();
    }

    public void addIntoReadBooks(Book book) {
        getReadBooks().add(book);
    }

    public void addIntoUnreadBooks(Book book) {
        getUnreadBooks().add(book);
    }
    //Getters
}

Book.java

public class Book {
    private final String id;
    private final String lang;
    private final String title;
    private final String author;

    public Book(String id, String lang, String title, String author) {
        this.id = id;
        this.lang = lang;
        this.title = title;
        this.author = author;
    }
    //Getters
}

如何决定该书应添加到哪个列表?

我的回答

不知何故,我设法忍受以下代码,它使用两个标志来跟踪访问的节点-

import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class ParseXML extends DefaultHandler {

    private Library lib;
    private boolean read;
    private boolean unread;

    public ParseXML(String file) throws ParserConfigurationException, SAXException, IOException {
        parse(file);
    }

    private void parse(String file) throws ParserConfigurationException, SAXException, IOException {
        final SAXParserFactory factory = SAXParserFactory.newInstance();
        final SAXParser parser = factory.newSAXParser();
        parser.parse(file, this);
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (qName.equals("read")) {
            read = false;
        }
        if (qName.equals("unread")) {
            unread = false;
        }
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if (qName.equals("library")) {
            String name = attributes.getValue("name");
            lib = new Library(name);
        }
        if (qName.equals("read")) {
            read = true;
        }
        if (qName.equals("unread")) {
            unread = true;
        }
        if (qName.equals("book")) {
            String id = attributes.getValue("id");
            String lang = attributes.getValue("lang");
            String title = attributes.getValue("title");
            String author = attributes.getValue("author");

            Book book = new Book(id, lang, title, author);

            // How to decide here, to which list this book should be added
            if (read && !unread) {
                lib.addIntoReadBooks(book);
                } else if (!read && unread) {
                lib.addIntoUnreadBooks(book);
            }
        }
    }

    /**
    * @return the lib
    */
    public Library getLibrary() {
        return lib;
    }
}

是否有更好的解决方案?

最佳答案

我不清楚这是否一定更好,但您可以保留 currentList您的 ParseXML 中的字段要操作的当前列表的类:

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class ParseXML extends DefaultHandler {

    private Library lib;
    private List<Book> extraBooks = new ArrayList<Book>();
    private List<Book> currentList = extraBooks;

    public ParseXML(String file) throws ParserConfigurationException, SAXException, IOException {
        parse(file);
    }

    private void parse(String file) throws ParserConfigurationException, SAXException, IOException {
        final SAXParserFactory factory = SAXParserFactory.newInstance();
        final SAXParser parser = factory.newSAXParser();
        parser.parse(file, this);
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (qName.equals("read") || qName.equals("unread"))
            currentList = extraBooks;
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if (qName.equals("library")) {
            String name = attributes.getValue("name");
            lib = new Library(name);
        }
        else if (qName.equals("read")) {
            currentList = lib.getReadBooks();
        }
        else if (qName.equals("unread")) {
            currentList = lib.getUnreadBooks();
        }
        else if (qName.equals("book")) {
            String id = attributes.getValue("id");
            String lang = attributes.getValue("lang");
            String title = attributes.getValue("title");
            String author = attributes.getValue("author");

            currentList.add(new Book(id, lang, title, author));
        }
    }

    /**
     * @return the lib
     */
    public Library getLibrary() {
        return lib;
    }

}

作为一种稍微不同的方法,您当然可以将列表和库名称保留为处理程序中的字段,并创建 LibraryendElement方法使用收集到的所有数据。

注意:(已过时)在此代码中,我使用了字段 extraBooks允许 <book>出现在 <read> 之外的标签和<unread>标签。它只是比仅仅设置 currentList 更安全一点。至nullendElement方法。我讨厌NullPointerException .

更新:

您不需要一次性字段 extraBooks .

您可以通过更改currentList的初始化来实现相同的空安全。至

private List<Book> currentList = new ArrayList<Book>();

endElement方法

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
    if (qName.equals("read") || qName.equals("unread"))
        currentList = new ArrayList<Book>();
}

关于java - Java中使用SAX解析器同时读取父级和子级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20814314/

相关文章:

java - Eclipse-PMD 全局配置规则集

c# - XmlDocument.Save() 在文档类型声明中插入空方括号

.net - 如何使用配置转换删除环境变量

java - 解析xml以查找java中的元素

python - 使用 SAX/Python 解析 XML + 无验证

java - 如何使监视目录服务监视多个文件夹

java - 分割字符串并计算 2 个子串的幂

java - 旋转 DataFrame - Spark SQL

xml - 如何将xml文件转换为R中的数据框

java - 使用 SAX 解析器解析包含特殊字符 "/"的值给出错误的输出