首页 文章

如何使用SAX解析器解析XML

提问于
浏览
58

我跟着这个tutorial .

它工作得很好,但我希望它返回一个包含所有字符串的数组,而不是带有最后一个元素的单个字符串 .

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

3 回答

  • 0

    因此,您希望构建一个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 Implementation

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

    首先必须使用 RootElementElement 对象定义XML结构 .

    在任何情况下,我都会使用POJO(Plain Old Java Objects)来保存您的数据 . 这将是所需的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的结构,然后只需将事件侦听器添加到适当的元素 . 缺点是代码变得非常重复和臃肿 .

    org.xml.sax Implementation

    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 以确保我们将正确的数据映射到正确的对象,如果遇到 </item> 标记,我们将 endElement 标志设置为 false . 表示我们已完成该项目标记 .

    在这个例子中,管理它很容易,但是必须用不同级别的重复标记来解析更复杂的结构变得棘手 . 在那里你必须使用Enums来设置你当前的状态和很多switch / case statemenet来检查你的位置,或者更优雅的解决方案是使用标签栈的某种标签跟踪器 .

  • 179

    在许多问题中,有必要为不同目的使用不同种类的xml文件 . 我不会试图 grab 这个无边无际的东西,从我自己的经验中说出我需要的一切 .

    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 vs 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(String namespaceURI,String localName,String qName,Attributes atts) . 这里namespaceURI - 名称空间,localName - 元素的本地名称,qName-本地名称与名称空间(用冒号分隔)和atts的组合 - 此元素的属性 . 在这种情况下,一切都很简单 . 只需使用qName'om并将其放入某个服务行thisElement即可 . 因此,我们标记我们现在的元素 .

    @Override 
    public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
       thisElement = qName; 
    }
    

    接下来,我们得出其含义的 Session 项目 . 这里包括方法characters() . 他的形式为:characters(char [] ch,int start,int length) . 一切都很清楚 . ch - 包含字符串本身在此元素中具有自我重要性的文件 . start和length - 指示行和长度起点的服务数 .

    @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数据说明了医生的类型 . 该类已定义并具有所有必需的setter-getters .

    下一个明显的元素结束,然后是下一个 . 负责结束endElement() . 它向我们发出信号,表明该项目已经结束,此时您可以执行任何操作 . 将继续 . 清洁元素 .

    @Override 
    public void endElement (String namespaceURI, String localName, String qName) throws SAXException {
       thisElement = ""; 
    }
    

    如此整个文档,我们来到文件的末尾 . 工作endDocument() . 在其中,我们可以释放内存,做一些diagnostichesuyu打印等 . 在我们的例子中,只需写下解析结束的内容 .

    @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);
    

  • 2
    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;
            }
        }
    }
    

相关问题