`
deepnighttwo
  • 浏览: 52130 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

解析XML——简单直接的来。

阅读更多

 

================== 闲扯的话================

对于现在越来越轻量级,越来越讲究速度和接近用户的应用来说,xml 确实有点复杂了。解析起来不仅耗内存,而且很复杂。这就好像花了几千块钱买了个MS Office ,但是80%feature 都用不着,还白白的耗着CPU 和内存。

个人觉得,设置文件用XML 其实挺好,因为设置文件一般并不太大,而且要求可读性强,还有很多乱七八糟的需求,可以利用XML 的力量。昨天搞chrome 的设置,发现chrome 的设置文件也是使用的json ,读起来也是轻松愉快。

前阵子做了个程序,需要解析豆瓣API 调用返回的XML 。真想说一句。。。豆瓣你别用XML 了。。。至少,提供个json 版的API 调用吧。

(以上谨代表个人观点)

=================== 正文=================

解析豆瓣返回的xml ,实在是不想用DOM 这个重量级的玩意。DOM 这个玩意,说它强大好还是说它官僚好呢。我倾向于使用SAXP 解析。但是现在面 临的一个问题是,我需要根据xml 节点的名字和属性值(一个或者多个)来决定当前的值是不是我想要的。这就麻烦一点点。第一反应是考虑xpath 。后来觉 得不如自己做一个得了,权当是按需定制一个轻量级的xpath

首先定义XMLSearchUnit 类,这个类的实例用来描述一个需要在XML 中搜索的值,值可以是xml 节点的值,或者是节点的属性。

package com.deepnighttwo.resourceresolver.douban.resolver.utils;

import java.util.HashMap;
import java.util.Map;

import org.xml.sax.Attributes;

/**
  *
  * Represent a search task. Target could be value of a node or attribute of the
  * node.
  *
  *
@author mzang
  */

public class XMLSearchUnit {

   
// attribute values to be matched during search
    private Map<String, String> attributeMatchValidation = new HashMap<String, String>();

   
// if target is an attribute, then set this member to be the attribute name.
    // if it is null or empty, then means the target is node value.
    private String expectedAttr;

    
// xml path, format is: /node_name/node_name/...
    private String xmlPath;

   
public XMLSearchUnit(String xmlPath) {
       
this .xmlPath = xmlPath;
    }

   
/**
     * if current node meets the search conditions or not. Meets means the path
     * is correct and the attribute value is matched.
     *
     *
@param path
     *
@param attributes
     *
@return
     */

   
public boolean match(String path, Attributes attributes) {
       
if (xmlPath.equals(path) == false ) {
           
return false ;
        }

       
for (String key : attributeMatchValidation.keySet()) {
            String exp = attributeMatchValidation.get(key);
            String compare = attributes.getValue(key);
           
if (exp.equalsIgnoreCase(compare) == false ) {
                
return false ;
            }
        }
       
return true ;
    }

   
public Map<String, String> getAttributeMatchValidation() {
       
return attributeMatchValidation;
    }

   
public void addAttributeValidation(String key, String value) {
         attributeMatchValidation.put(key, value);
    }

   
public String getXmlPath() {
       
return xmlPath;
    }

   
public void setAttributeMatchValidation(
            Map<String, String> attributeMatchValidation) {
       
this .attributeMatchValidation = attributeMatchValidation;
    }

   
public String getExpectedAttr() {
       
return expectedAttr;
    }

   
/**
     * if target is node value, then set expectedAttr to null. if target is an
     * attribute value, set it to be the attribute name.
     *
     *
@param expectedAttr
     */

   
public void setExpectedAttr(String expectedAttr) {
       
this .expectedAttr = expectedAttr;
    }

   
/**
     * hash code can be cached if all properties are not be be changed.
     */

    @Override
   
public int hashCode() {
       
final int prime = 31;
       
int result = 1;
        result = prime
                * result
                + ((attributeMatchValidation ==
null ) ? 0
                        : attributeMatchValidation.hashCode());
        result = prime * result
                + ((expectedAttr ==
null ) ? 0 : expectedAttr.hashCode());
        result = prime * result + ((xmlPath ==
null ) ? 0 : xmlPath.hashCode());
       
return result;
    }

    @Override
   
public boolean equals(Object obj) {
       
if ( this == obj)
           
return true ;
       
if (obj == null )
           
return false ;
       
if (getClass() != obj.getClass())
           
return false ;
        XMLSearchUnit other = (XMLSearchUnit) obj;
       
if (attributeMatchValidation == null ) {
           
if (other.attributeMatchValidation != null )
               
return false ;
        }
else if (!attributeMatchValidation
                .equals(other.attributeMatchValidation))
           
return false ;
       
if (expectedAttr == null ) {
           
if (other.expectedAttr != null )
               
return false ;
        }
else if (!expectedAttr.equals(other.expectedAttr))
           
return false ;
       
if (xmlPath == null ) {
           
if (other.xmlPath != null )
               
return false ;
        }
else if (!xmlPath.equals(other.xmlPath))
           
return false ;
       
return true ;
    }

}

这个类比较简单。就是用一个hashmap 保待匹配的attribut 键值对,用一个字符串表示期待的attribute name ,用一个字符串表示期待的node path

然后就是如何在SAXP 里用到这个类的实例去搜索了。

package com.deepnighttwo.resourceresolver.douban.resolver.utils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

/**
  *
  * SAXP parser working with XMLSearchUnit.
  *
  *
@author mzang
  */


public class DoubanSearchParser extends DefaultHandler {

   
// create and initial search units
    public static final XMLSearchUnit DETAILS_LINK_API_PATH = new XMLSearchUnit(
            "/feed/entry/id");

   
public static final XMLSearchUnit DETAILS_CONTENT_PATH = new XMLSearchUnit(
            "/entry/summary");

   
public static final XMLSearchUnit DETAILS_TITLE_PATH = new XMLSearchUnit(
            "/entry/title");

   
public static final XMLSearchUnit DETAILS_CHINESE_NAME_PATH = new XMLSearchUnit(
            "/entry/db:attribute");

   
public static final XMLSearchUnit DETAILS_RATINGE_PATH = new XMLSearchUnit(
            "/entry/gd:rating");

   
public static final XMLSearchUnit DETAILS_RATINGE_RATER_COUNT_PATH = new XMLSearchUnit(
             "/entry/gd:rating");

   
public static final XMLSearchUnit DETAILS_LINK_URL_PATH = new XMLSearchUnit(
            "/feed/entry/link");

   
static {
        DETAILS_LINK_URL_PATH.addAttributeValidation("rel", "alternate");
        DETAILS_LINK_URL_PATH.setExpectedAttr("href");

        DETAILS_CHINESE_NAME_PATH.addAttributeValidation("lang", "zh_CN");
        DETAILS_CHINESE_NAME_PATH.addAttributeValidation("name", "aka");

        DETAILS_RATINGE_PATH.setExpectedAttr("average");

         DETAILS_RATINGE_RATER_COUNT_PATH.setExpectedAttr("numRaters");

    }

   
// a map to store the XMLSearchUnit and value
    private Map<XMLSearchUnit, String> results = new HashMap<XMLSearchUnit, String>();

   
// a counter of search unit. if it is 0, then all search unit finds a match
    // value and the result of the XML will be skipped.
    private int count = 0;

   
private StringBuilder path = new StringBuilder();

   
private static final String pathSeparater = "/";

   
private XMLSearchUnit[] searchUnits;

    List<XMLSearchUnit> foundItems =
new ArrayList<XMLSearchUnit>();

   
/**
     * constructor, accept XML input stream, 0 or more search unit instances.
     *
     *
@param input
     *
@param expectedPath
     *
@return
     */

    
public Map<XMLSearchUnit, String> parseResults(InputStream input,
            XMLSearchUnit... expectedPath) {
       
for (XMLSearchUnit search : expectedPath) {
            results.put(search,
null );
        }

        searchUnits = expectedPath;

         count = expectedPath.length;

        XMLReader xmlReader =
null ;
       
try {
            SAXParserFactory spfactory = SAXParserFactory.newInstance();
            spfactory.setValidating(
false );
            SAXParser saxParser = spfactory.newSAXParser();
            xmlReader = saxParser.getXMLReader();
            xmlReader.setContentHandler(
this );
            xmlReader.parse(
new InputSource(input));
        }
catch (Exception e) {
            System.err.println(e);
            System.exit(1);
         }
       
return results;
    }

   
private void addToPath(String addPath) {
        path.append(pathSeparater).append(addPath.toLowerCase());
    }

   
private void popPath() {
       
int index = path.lastIndexOf(pathSeparater);
       
// String removedPath = path.substring(index);
        path.delete(index, path.length());
    }

    @Override
   
public void startElement(String uri, String localName, String qName,
            Attributes attributes)
throws SAXException {
        foundItems.clear();
        
if (count == 0) {
           
return ;
        }

       
// update path
        addToPath(qName);

        List<XMLSearchUnit> foundAttrItems =
null ;

       
// check if current node matches search units. if it is a node value
        // search, then store it in a member variable named foundItems because
        // the value of the node is known only when reaches the end of the
        // node.but for attribute search, it value is known here. So then are
        // put in a local variable list named foundAttrItems.
        for (XMLSearchUnit unit : searchUnits) {
           
if (unit.match(path.toString(), attributes) == true ) {

               
if (unit.getExpectedAttr() == null ) {
                    foundItems.add(unit);
                }
else {
                    
if (foundAttrItems == null ) {
                        foundAttrItems =
new ArrayList<XMLSearchUnit>();
                    }
                    foundAttrItems.add(unit);
                }
            }
        }
       
// if no attribute match, return.
        if (foundAttrItems == null ) {
           
return ;
        }

       
// fill search unit value using attribute value. update count.
        for (XMLSearchUnit attrUnit : foundAttrItems) {
            String attrValue = attributes.getValue(attrUnit.getExpectedAttr());
           
if (results.get(attrUnit) == null ) {
                count--;
            }
            results.put(attrUnit, attrValue);
            count--;
        }
    }

   
/**
     * if current node matches, the the node value is useful, store it.
     */

    @Override
   
public void characters( char [] ch, int start, int length)
           
throws SAXException {
       
if (count == 0) {
           
return ;
        }
       
if (foundItems.size() == 0) {
            
return ;
        }

       
for (XMLSearchUnit unit : foundItems) {
            String content =
new String(ch, start, length);
           
if (results.get(unit) == null ) {
                count--;
            }
            results.put(unit, content);
         }
    }

    @Override
   
public void endElement(String uri, String localName, String qName)
           
throws SAXException {
        foundItems.clear();
       
if (count == 0) {
           
return ;
        }
        popPath();
    }
}

 

分享到:
评论

相关推荐

    java解析xml——dom

    ### Java解析XML——DOM详解 #### 一、DOM解析概念 **Document Object Model (DOM)**是一种平台和语言中立的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。DOM最初是为HTML设计的,但后来也被...

    XML解析器————

    例如,对于DOM解析,可以创建`DOMParser`实例,然后使用`parse()`方法解析XML文档;对于SAX解析,可以实现`ContentHandler`接口,并注册到`SAXParser`中。同时,可以通过`XMLSchemaValidator`进行XML Schema验证。 ...

    Android XML解析——Sax解析XML

    ### Android中使用SAX解析XML 1. **引入库**:在Android项目中,SAX解析器已经内置在`org.xml.sax`包中,无需额外导入库。 2. **创建ContentHandler**:创建一个实现了`org.xml.sax.ContentHandler`接口的类,重写...

    c++ xml解析工具——tinyxml

    TinyXML库提供了一种简洁的方式来读取、修改和写入XML文档,使得开发者无需深入理解XML解析的底层细节就能处理XML数据。 TinyXML库主要包含以下组件: 1. **TiXMLDocument**:这是TinyXML的核心类,代表整个XML...

    xml——————表单资源

    在处理XML时,我们通常会用到XML解析器,它们分为DOM(Document Object Model)解析器、SAX(Simple API for XML)解析器和StAX(Streaming API for XML)解析器。DOM解析器将整个XML文档加载到内存中,形成一个树形...

    XML——sax解析 极速入门易懂示例

    首先,我们需要通过`XMLReaderFactory`获取一个`XMLReader`实例,然后设置事件处理器(如`ContentHandler`和`ErrorHandler`),最后调用`parse()`方法解析XML文件。 2. **SAXParserFactory**:这是JAXP(Java API ...

    Android XML解析—— Pull解析XML(待完善)

    - **适合解析简单结构的XML**:对于结构复杂、嵌套深度大的XML,Pull解析可能不如DOM或SAX解析直观。 在实际开发中,如Android的布局文件解析、配置文件读取或者从网络获取XML数据时,都可以使用Pull解析器进行处理...

    Android之PULL解析XML文件——新浪微博客户端首页效果

    在本主题"Android之PULL解析XML文件——新浪微博客户端首页效果"中,我们将深入探讨如何利用PULL解析器(PullParser)来处理XML数据,从而实现类似新浪微博客户端首页的动态效果。这种效果通常包括新闻标题、摘要、...

    解析xml的jar包

    解析XML是将XML文档转换为程序可以理解的数据结构的关键步骤。本文将深入探讨XML解析的基本概念、常用方法以及相关的Java库——JDOM。 XML文档由一系列元素构成,每个元素都包含标签、属性和内容。解析XML的过程...

    XML的解析之——使用Digester

    本文将深入探讨如何使用Apache的 Digester 库来解析XML文档,这是一款强大的工具,能够将XML数据映射到Java对象,简化了处理XML的过程。 Digester 是Apache Commons项目的一部分,它提供了一种规则驱动的方法来处理...

    解析XML特殊字符方法

    有两种主要方法来解析XML中的特殊字符: **方法一:使用实体引用** 实体引用是XML中最常见的处理特殊字符的方式。当你需要在XML文档中插入特殊字符时,可以使用对应的实体引用。比如,如果你想在文本中包含一个...

    纯C语言XML解析xmlparse.c&xmlparse;.h

    xmlparse.c文件包含了解析XML文档的主要实现代码。它通常会通过读取XML文档的字节流,逐步构建XML元素树。解析过程包括词法分析(Tokenization)、语法分析(Parsing)和语义分析(Semantic Analysis)。词法分析将...

    python解析xml文件

    本文将详细介绍如何使用两种流行的方法——`MiniDom`和`ElementTree`来解析XML文件。 #### 1. 通过 MiniDom 库解析 XML 文件 `MiniDom`是Python标准库中的一部分,它提供了DOM(Document Object Model)接口,允许...

    android开发之xml文件操作——xml创建和pull解析xml

    本项目主要关注的是XML的创建和使用Pull解析器来解析XML,这是Android系统中处理XML数据的一种高效方法。接下来,我们将详细讨论这两个知识点。 首先,XML(Extensible Markup Language)是一种用于标记数据的语言...

    使用Android自带的XML解析器PULL解析器简单的解析xml

    下面是一个简单的使用PULL解析器解析XML并显示内容在`TextView`上的步骤: 1. 引入必要的库:在Android项目中,`XmlPullParser`是内置的,无需额外导入库。 2. 创建`XmlPullParser`实例:通常,我们可以使用`...

    TinyXML——类库+doc

    例如,解析XML文档通常从创建一个TiXMLDocument实例开始,然后调用LoadFile()或ReadFile()方法加载XML文件。一旦文档被加载,你可以通过元素、属性和文本对象的指针来遍历和操作XML结构。例如,你可以使用...

    Android中,使用SAX和PULL解析天气预报XML

    该文章详细介绍了在Android环境下如何使用SAX和PULL解析XML,包括代码示例和步骤说明,对于初学者来说非常有帮助。 最后,压缩包中的"Weather"文件很可能是示例的天气预报XML数据。通过实际解析这个文件,你可以更...

    使用java解析XML文件,解析完之后将解析结果导入mysql数据库中

    在Java编程环境中,解析XML文件是一项常见的任务,特别是在数据处理和集成中。XML(Extensible Markup Language)是一种结构化数据格式,广泛用于存储和传输数据。本教程将介绍如何使用Java解析XML文件,并将解析...

    adroid解析XML三种方式——源码分析

    本篇文章将深入探讨Android解析XML的三种主要方法:DOM、SAX和Pull解析器,并结合源码进行分析,帮助开发者理解它们的工作原理和适用场景。 1. DOM解析: DOM(Document Object Model)解析器将整个XML文档加载到...

Global site tag (gtag.js) - Google Analytics