我有一个非常小的 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;
}
}
作为一种稍微不同的方法,您当然可以将列表和库名称保留为处理程序中的字段,并创建 Library
在 endElement
方法使用收集到的所有数据。
注意:(已过时)在此代码中,我使用了字段 extraBooks
允许 <book>
出现在 <read>
之外的标签和<unread>
标签。它只是比仅仅设置 currentList
更安全一点。至null
在 endElement
方法。我讨厌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/