gpt4 book ai didi

java - 如何使用 SAX 解析器解析 XML

转载 作者:IT老高 更新时间:2023-10-28 13:23:50 26 4
gpt4 key购买 nike

我正在关注 tutorial .

效果很好,但我希望它返回一个包含所有字符串的数组,而不是一个包含最后一个元素的字符串。

任何想法如何做到这一点?

最佳答案

所以你想构建一个 XML 解析器来解析像这样的 RSS 提要。

<rss version="0.92">
<channel>
<title>MyTitle</title>
<link>http://myurl.com</link>
<description>MyDescription</description>
<lastBuildDate>SomeDate</lastBuildDate>
<docs>http://someurl.com</docs>
<language>SomeLanguage</language>

<item>
<title>TitleOne</title>
<description><![CDATA[Some text.]]></description>
<link>http://linktoarticle.com</link>
</item>

<item>
<title>TitleTwo</title>
<description><![CDATA[Some other text.]]></description>
<link>http://linktoanotherarticle.com</link>
</item>

</channel>
</rss>

现在您有两个可以使用的 SAX 实现。要么使用 org.xml.saxandroid.sax执行。在发布一个短手示例后,我将解释两者的优缺点。

android.sax 实现

让我们从 android.sax 开始吧。实现。

您首先必须使用 RootElement 定义 XML 结构。和 Element对象。

无论如何,我都会使用 POJO(普通旧 Java 对象)来保存您的数据。这将是所需的 POJO。

Channel.java

public class Channel implements Serializable {

private Items items;
private String title;
private String link;
private String description;
private String lastBuildDate;
private String docs;
private String language;

public Channel() {
setItems(null);
setTitle(null);
// set every field to null in the constructor
}

public void setItems(Items items) {
this.items = items;
}

public Items getItems() {
return items;
}

public void setTitle(String title) {
this.title = title;
}

public String getTitle() {
return title;
}
// rest of the class looks similar so just setters and getters
}

这个类实现了 Serializable接口(interface),因此您可以将其放入 Bundle并用它做点什么。

现在我们需要一个类来保存我们的项目。在这种情况下,我将扩展 ArrayList类。

Items.java

public class Items extends ArrayList<Item> {

public Items() {
super();
}

}

这就是我们的元素容器。我们现在需要一个类来保存每个项目的数据。

Item.java

public class Item implements Serializable {

private String title;
private String description;
private String link;

public Item() {
setTitle(null);
setDescription(null);
setLink(null);
}

public void setTitle(String title) {
this.title = title;
}

public String getTitle() {
return title;
}

// same as above.

}

例子:

public class Example extends DefaultHandler {

private Channel channel;
private Items items;
private Item item;

public Example() {
items = new Items();
}

public Channel parse(InputStream is) {
RootElement root = new RootElement("rss");
Element chanElement = root.getChild("channel");
Element chanTitle = chanElement.getChild("title");
Element chanLink = chanElement.getChild("link");
Element chanDescription = chanElement.getChild("description");
Element chanLastBuildDate = chanElement.getChild("lastBuildDate");
Element chanDocs = chanElement.getChild("docs");
Element chanLanguage = chanElement.getChild("language");

Element chanItem = chanElement.getChild("item");
Element itemTitle = chanItem.getChild("title");
Element itemDescription = chanItem.getChild("description");
Element itemLink = chanItem.getChild("link");

chanElement.setStartElementListener(new StartElementListener() {
public void start(Attributes attributes) {
channel = new Channel();
}
});

// Listen for the end of a text element and set the text as our
// channel's title.
chanTitle.setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
channel.setTitle(body);
}
});

// Same thing happens for the other elements of channel ex.

// On every <item> tag occurrence we create a new Item object.
chanItem.setStartElementListener(new StartElementListener() {
public void start(Attributes attributes) {
item = new Item();
}
});

// On every </item> tag occurrence we add the current Item object
// to the Items container.
chanItem.setEndElementListener(new EndElementListener() {
public void end() {
items.add(item);
}
});

itemTitle.setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
item.setTitle(body);
}
});

// and so on

// here we actually parse the InputStream and return the resulting
// Channel object.
try {
Xml.parse(is, Xml.Encoding.UTF_8, root.getContentHandler());
return channel;
} catch (SAXException e) {
// handle the exception
} catch (IOException e) {
// handle the exception
}

return null;
}

}

如您所见,这是一个非常简单的示例。使用 android.sax 的主要优势SAX 实现是您可以定义必须解析的 XML 的结构,然后只需将事件监听器添加到适当的元素。缺点是代码非常重复和臃肿。

org.xml.sax 实现

org.xml.sax SAX 处理程序实现有点不同。

这里您没有指定或声明您的 XML 结构,而只是监听事件。最广泛使用的是以下事件:

  • 文档开始
  • 文档结束
  • 元素开始
  • 元素结束
  • 元素开始和元素结束之间的字符

使用上面的 Channel 对象的示例处理程序实现如下所示。

例子

public class ExampleHandler extends DefaultHandler {

private Channel channel;
private Items items;
private Item item;
private boolean inItem = false;

private StringBuilder content;

public ExampleHandler() {
items = new Items();
content = new StringBuilder();
}

public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
content = new StringBuilder();
if(localName.equalsIgnoreCase("channel")) {
channel = new Channel();
} else if(localName.equalsIgnoreCase("item")) {
inItem = true;
item = new Item();
}
}

public void endElement(String uri, String localName, String qName)
throws SAXException {
if(localName.equalsIgnoreCase("title")) {
if(inItem) {
item.setTitle(content.toString());
} else {
channel.setTitle(content.toString());
}
} else if(localName.equalsIgnoreCase("link")) {
if(inItem) {
item.setLink(content.toString());
} else {
channel.setLink(content.toString());
}
} else if(localName.equalsIgnoreCase("description")) {
if(inItem) {
item.setDescription(content.toString());
} else {
channel.setDescription(content.toString());
}
} else if(localName.equalsIgnoreCase("lastBuildDate")) {
channel.setLastBuildDate(content.toString());
} else if(localName.equalsIgnoreCase("docs")) {
channel.setDocs(content.toString());
} else if(localName.equalsIgnoreCase("language")) {
channel.setLanguage(content.toString());
} else if(localName.equalsIgnoreCase("item")) {
inItem = false;
items.add(item);
} else if(localName.equalsIgnoreCase("channel")) {
channel.setItems(items);
}
}

public void characters(char[] ch, int start, int length)
throws SAXException {
content.append(ch, start, length);
}

public void endDocument() throws SAXException {
// you can do something here for example send
// the Channel object somewhere or whatever.
}

}

老实说,我无法真正告诉您这个处理程序实现相对于 android.sax 的任何真正优势。一。然而,我可以告诉你现在应该很明显的缺点。查看 startElement 中的 else if 语句方法。由于我们有标签 <title> , linkdescription我们必须在目前的 XML 结构中进行跟踪。也就是说,如果我们遇到 <item>我们设置的起始标签inItem标记为 true以确保我们将正确的数据映射到正确的对象并在 endElement方法我们将该标志设置为false如果我们遇到 </item>标签。表示我们已完成该项目标签。

在这个例子中,很容易管理它,但是必须解析一个具有不同级别的重复标签的更复杂的结构变得很棘手。例如,您必须使用 Enums 来设置当前状态,并使用许多 switch/case 语句来检查您的位置,或者更优雅的解决方案是使用标签堆栈的某种标签跟踪器。

关于java - 如何使用 SAX 解析器解析 XML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4827344/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com