[英]How to parse XML using the SAX parser
因此,您想构建一个XML解析器来解析这样的RSS feed。
<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.sax
或android.sax
实现。 在发布简短的示例后,我将解释两者的优点和缺点。
android.sax实现
让我们从android.sax
实现开始。
首先,您必须使用RootElement
和Element
对象定义XML结构。
无论如何,我都会使用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
接口,因此您可以将其放入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的结构,然后将事件侦听器添加到适当的元素。 缺点是代码变得很重复且and肿。
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>
, link
和description
,因此必须在当前的XML结构中进行跟踪。 也就是说,如果遇到<item>
起始标记,则将inItem
标志设置为true
以确保将正确的数据映射到正确的对象,在endElement
方法中,如果遇到</item>
标记,则将该标志设置为false
。 表示我们已完成该商品标签。
在此示例中,这很容易管理,但是必须使用重复级别不同的标签来解析更复杂的结构变得棘手。 例如,您必须使用Enums来设置当前状态,并使用很多开关/案例状态菜单来检查您的位置,或者更优雅的解决方案是使用标签栈的某种标签跟踪器。
在许多问题中,有必要出于不同目的使用不同种类的xml文件。 我不会试图把握巨大的空间,从我自己的经验中告诉我我需要这一切。
Java,也许是我最喜欢的编程语言。 此外,您可以解决任何问题并且不需要骑自行车,这一事实进一步增强了这种爱。
因此,我花了很多钱来创建一台运行数据库的客户端服务器,该客户端服务器允许客户端远程在数据库服务器中进行输入。 不必检查输入数据等,但这不是关于此的。
作为工作原理,我毫不犹豫地选择了以xml文件形式传输信息。 以下类型的:
<? xml version = "1.0" encoding = "UTF-8" standalone = "no"?>
<doc>
<id> 3 </ id>
<fam> Ivanov </ fam>
<name> Ivan </ name>
<otc> I. </ otc>
<dateb> 10-03-2005 </ dateb>
<datep> 10-03-2005 </ datep>
<datev> 10-03-2005 </ datev>
<datebegin> 09-06-2009 </ datebegin>
<dateend> 10-03-2005 </ dateend>
<vdolid> 1 </ vdolid>
<specid> 1 </ specid>
<klavid> 1 </ klavid>
<stav> 2.0 </ stav>
<progid> 1 </ progid>
</ doc>
除了说这是有关医生机构的信息以外,使其他内容的阅读更容易。 姓,名,唯一ID等。 一般来说,数据系列。 该文件安全地放在服务器端,然后开始解析该文件。
在两个选项解析(SAX与DOM)中,我选择SAX来考虑以下事实:他工作得更聪明,而他是我第一个落入手:)
所以。 如您所知,要成功使用解析器,我们需要重写DefaultHandler的所需方法。 首先,连接所需的软件包。
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax. *;
现在我们可以开始编写解析器了
public class SAXPars extends DefaultHandler {
...
}
让我们从方法startDocument()开始。 顾名思义,他对文档开头的事件做出反应。 在这里您可以挂起各种操作,例如内存分配或重置值,但是我们的示例非常简单,因此只需标记一条适当的消息开始工作即可:
Override
public void startDocument () throws SAXException {
System.out.println ("Start parse XML ...");
}
下一个。 解析器遍历文档是否符合其结构要素。 启动方法startElement()。 实际上,他的外观是:startElement(字符串namespaceURI,字符串localName,字符串qName,属性atts)。 这里的namespaceURI-名称空间,localName-元素的本地名称,qName-具有名称空间的本地名称(用冒号分隔)和atts-此元素的属性的组合。 在这种情况下,一切简单。 只需使用qName'om并将其放入服务行thisElement中即可。 因此,我们标记了当前元素所在的位置。
@Override
public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
thisElement = qName;
}
接下来,我们要讨论会议项目的意义。 这里包括方法字符()。 他具有以下形式:字符(char [] ch,int开头,int长度)。 好了,这里一切都清楚了。 ch-包含字符串本身在此元素内的自重要性的文件。 起点和长度-服务编号,指示直线和长度中的起点。
@Override
public void characters (char [] ch, int start, int length) throws SAXException {
if (thisElement.equals ("id")) {
doc.setId (new Integer (new String (ch, start, length)));
}
if (thisElement.equals ("fam")) {
doc.setFam (new String (ch, start, length));
}
if (thisElement.equals ("name")) {
doc.setName (new String (ch, start, length));
}
if (thisElement.equals ("otc")) {
doc.setOtc (new String (ch, start, length));
}
if (thisElement.equals ("dateb")) {
doc.setDateb (new String (ch, start, length));
}
if (thisElement.equals ("datep")) {
doc.setDatep (new String (ch, start, length));
}
if (thisElement.equals ("datev")) {
doc.setDatev (new String (ch, start, length));
}
if (thisElement.equals ("datebegin")) {
doc.setDatebegin (new String (ch, start, length));
}
if (thisElement.equals ("dateend")) {
doc.setDateend (new String (ch, start, length));
}
if (thisElement.equals ("vdolid")) {
doc.setVdolid (new Integer (new String (ch, start, length)));
}
if (thisElement.equals ("specid")) {
doc.setSpecid (new Integer (new String (ch, start, length)));
}
if (thisElement.equals ("klavid")) {
doc.setKlavid (new Integer (new String (ch, start, length)));
}
if (thisElement.equals ("stav")) {
doc.setStav (new Float (new String (ch, start, length)));
}
if (thisElement.equals ("progid")) {
doc.setProgid (new Integer (new String (ch, start, length)));
}
}
是的。 我差点忘了。 折叠naparsennye数据的目的在于说医生的类型。 此类已定义,并且具有所有必需的setters-getters。
下一个明显的元素结束,然后是下一个。 负责结束endElement()。 它向我们发出信号,该项目已结束,您现在可以执行任何操作。 将继续。 清洗元素。
@Override
public void endElement (String namespaceURI, String localName, String qName) throws SAXException {
thisElement = "";
}
这样,整个文档就到了文件末尾。 工作endDocument()。 在其中,我们可以释放内存,进行一些诊断性打印,等等。在我们的情况下,只需写出解析结束的内容即可。
@Override
public void endDocument () {
System.out.println ("Stop parse XML ...");
}
因此,我们有了一个类来解析xml我们的格式。 这是全文:
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax. *;
public class SAXPars extends DefaultHandler {
Doctors doc = new Doctors ();
String thisElement = "";
public Doctors getResult () {
return doc;
}
@Override
public void startDocument () throws SAXException {
System.out.println ("Start parse XML ...");
}
@Override
public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
thisElement = qName;
}
@Override
public void endElement (String namespaceURI, String localName, String qName) throws SAXException {
thisElement = "";
}
@Override
public void characters (char [] ch, int start, int length) throws SAXException {
if (thisElement.equals ("id")) {
doc.setId (new Integer (new String (ch, start, length)));
}
if (thisElement.equals ("fam")) {
doc.setFam (new String (ch, start, length));
}
if (thisElement.equals ("name")) {
doc.setName (new String (ch, start, length));
}
if (thisElement.equals ("otc")) {
doc.setOtc (new String (ch, start, length));
}
if (thisElement.equals ("dateb")) {
doc.setDateb (new String (ch, start, length));
}
if (thisElement.equals ("datep")) {
doc.setDatep (new String (ch, start, length));
}
if (thisElement.equals ("datev")) {
doc.setDatev (new String (ch, start, length));
}
if (thisElement.equals ("datebegin")) {
doc.setDatebegin (new String (ch, start, length));
}
if (thisElement.equals ("dateend")) {
doc.setDateend (new String (ch, start, length));
}
if (thisElement.equals ("vdolid")) {
doc.setVdolid (new Integer (new String (ch, start, length)));
}
if (thisElement.equals ("specid")) {
doc.setSpecid (new Integer (new String (ch, start, length)));
}
if (thisElement.equals ("klavid")) {
doc.setKlavid (new Integer (new String (ch, start, length)));
}
if (thisElement.equals ("stav")) {
doc.setStav (new Float (new String (ch, start, length)));
}
if (thisElement.equals ("progid")) {
doc.setProgid (new Integer (new String (ch, start, length)));
}
}
@Override
public void endDocument () {
System.out.println ("Stop parse XML ...");
}
}
我希望该主题有助于轻松呈现SAX解析器的本质。
不要严格地评判第一篇文章:)我希望至少有人有用。
UPD:要运行此解析器,可以使用以下代码:
SAXParserFactory factory = SAXParserFactory.newInstance ();
SAXParser parser = factory.newSAXParser ();
SAXPars saxp = new SAXPars ();
parser.parse (new File ("..."), saxp);
public class MainActivity extends AppCompatActivity {
ListView lvPcsPost;
ArrayList<String> name;
ArrayList<String> price;
ArrayList<String> Description;
LayoutInflater layoutInflater;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvPcsPost = (ListView) findViewById(R.id.lvPcsPost);
name = new ArrayList<>();
price = new ArrayList<>();
Description = new ArrayList<>();
new PostAsync().execute();
}
class PostAsync extends AsyncTask<Void, Void, Void> {
ProgressDialog pd;
XMLHelper helper;
@Override
protected void onPreExecute() {
pd = ProgressDialog.show(MainActivity.this, "", "Loading...", true, false);
}
@Override
protected Void doInBackground(Void... arg0) {
helper = new XMLHelper();
helper.get();
return null;
}
@Override
protected void onPostExecute(Void result) {
PostBaseAdapter postBaseAdapter = new PostBaseAdapter();
lvPcsPost.setAdapter(postBaseAdapter);
pd.dismiss();
}
}
public class XMLHelper extends DefaultHandler {
private String URL_MAIN = "http://uat.winitsoftware.com/ThemeManager/Data/Products/Products.xml";
String TAG = "XMLHelper";
Boolean currTag = false;
String currTagVal = "";
public void get() {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser mSaxParser = factory.newSAXParser();
XMLReader mXmlReader = mSaxParser.getXMLReader();
mXmlReader.setContentHandler(this);
InputStream mInputStream = new URL(URL_MAIN).openStream();
mXmlReader.parse(new InputSource(mInputStream));
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.getMessage());
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (currTag) {
currTagVal = currTagVal + new String(ch, start, length);
currTag = false;
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
currTag = false;
if (localName.equalsIgnoreCase("Name"))
name.add(currTagVal);
else if (localName.equalsIgnoreCase("Description"))
Description.add(currTagVal);
else if (localName.equalsIgnoreCase("Price"))
price.add(currTagVal);
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
Log.i(TAG, "TAG: " + localName);
currTag = true;
currTagVal = "";
if (localName.equals("Products"));
}
}
public class PostBaseAdapter extends BaseAdapter {
public PostBaseAdapter() {
}
@Override
public int getCount() {
return name.size();
}
@Override
public Object getItem(int position) {
return name.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
layoutInflater = LayoutInflater.from(getApplicationContext());
convertView = layoutInflater.inflate(R.layout.list_item_post, parent, false);
TextView txtPrice = (TextView) convertView.findViewById(R.id.txtPrice);
TextView txtDescription = (TextView) convertView.findViewById(R.id.txtDescription);
TextView txtName = (TextView) convertView.findViewById(R.id.txtName);
ImageView image = (ImageView) convertView.findViewById(R.id.Image);
ImageView bigImage = (ImageView) convertView.findViewById(R.id.BigImage);
txtPrice.setText("Price : "+price.get(position));
txtDescription.setText("Description : "+Description.get(position));
txtName.setText("Name : "+name.get(position));
return convertView;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.