Java如何使用SAX(Simple API for XML)解析XML呢?

2023-11-03

转自:

Java如何使用SAX(Simple API for XML)解析XML呢?

下文讲述使用SAX解析xml文档的方法分享,如下所示

SAX简介

SAX用于加载文档到内存中,它是采用事件驱动的API(Observer模式)
他按照xml文件的顺序一步一步的来解析,用户只需要注册自己感兴趣的事件即可
SAX提供EntityResolver, DTDHandler, ContentHandler, ErrorHandler接口,
分别用于监听解析实体事件、DTD处理事件、正文处理事件和处理出错事件,与AWT类似,
SAX还提供了一个对这4个接口默认的类DefaultHandler(这里的默认实现,其实就是一个空方法),
一般只要继承DefaultHandler,重写自己感兴趣的事件即可

SAX解析xml的原理:
   Sax采用事件驱动的方式解析文档
      类似于io读取的向下读取操作
 在Sax的解析过程中,读取到文档开头、结尾,元素的开头和结尾都会触发一些回调方法
 我们可以在这些回调方法中进行相应事件处理
 如:startDocument()
    endDocument()
    startElement()
    endElement

SAX XML解析步骤

Java Sax在解析xml文件之前
需先了解xml文件的节点的种类
一种是ElementNode,一种是TextNode
例:user.xml

<?xml version="1.0" encoding="UTF-8"?>  
<users>  
    <user id="12">  
        <name>maomao</name>  
        <age>18</age>  
    </user>  
    <user id="15">  
        <name>xiaoxiao</name>  
        <age>20</age>  
    </user>  
</users> 

<users>、<user>这种节点就属于ElementNode
maomao这种就属于TextNode
下面结合一张图来详细讲解Sax解析


Java SAX XML解析

将xml载入SAX,然后解析
//TestClass.java

public class SaxParseService extends DefaultHandler{  
    private List<User> users = null;  
    private User user = null;  
    private String preTag = null;//作用是记录解析时的上一个节点名称  
      
    public List<User> getUsers(InputStream xmlStream) throws Exception{  
        SAXParserFactory factory = SAXParserFactory.newInstance();  
        SAXParser parser = factory.newSAXParser();  
        SaxParseService handler = new SaxParseService();  
        parser.parse(xmlStream, handler);  
        return handler.getUsers();  
    }  
      
    public List<User> getUsers(){  
        return users;  
    }  
      
    @Override  
    public void startDocument() throws SAXException {  
        users = new ArrayList<User>();  
    }  
  
    @Override  
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {  
        if("user".equals(qName)){  
            user = new User();  
            user.setId(Integer.parseInt(attributes.getValue(0)));  
        }  
        preTag = qName;//将正在解析的节点名称赋给preTag  
    }  
  
    @Override  
    public void endElement(String uri, String localName, String qName)  
            throws SAXException {  
        if("user".equals(qName)){  
            users.add(user);  
            user = null;  
        }  
        preTag = null;/**当解析结束时置为空。这里很重要,例如,当图中画3的位置结束后,会调用这个方法 
        ,如果这里不把preTag置为null,根据startElement(....)方法,preTag的值还是user,当文档顺序读到图 
        中标记4的位置时,会执行characters(char[] ch, int start, int length)这个方法,而characters(....)方 
        法判断preTag!=null,会执行if判断的代码,这样就会把空值赋值给user,这不是我们想要的。*/  
    }  
      
    @Override  
    public void characters(char[] ch, int start, int length) throws SAXException {  
        if(preTag!=null){  
            String content = new String(ch,start,length);  
            if("name".equals(preTag)){  
                user.setName(content);  
            }else if("age".equals(preTag)){  
                user.setAge(Int.parseInt(content));  
            }  
        }  
    }  
}  

//User.java 主要是用来组装数据
public class User {  
    private int id;  
    private String name;  
    private int age;  
    public int getId() {  
        return id;  
    }  
    public void setId(int id) {  
        this.id = id;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getAge() {  
        return age;  
    }  
    public void setAge(int age) {  
        this.age = age;  
    }  
    @Override  
    public String toString(){  
        return this.id+":"+this.name+":"+this.age;  
    }  
} 

 
//ParseTest
public class ParseTest extends TestCase{  
    public void testSAX() throws Throwable{  
        SaxParseService sax = new SaxParseService();  
        InputStream input = this.getClass().getClassLoader().getResourceAsStream("user.xml");  
        List<User> users = sax.getUsers(input);  
        for(User user : users){  
            System.out.println(user.toString());  
        }  
    }  
}
xml文件被Sax解析器载入
由于Sax解析是按照xml文件的顺序来解析
当读入<?xml.....>时,会调用startDocument()方法
当读入<users>的时候,由于它是个ElementNode,
所以会调用startElement(String uri, String localName, String qName, Attributes attributes) 方法,
其中第二个参数就是节点的名称
------------------------------------
注意事项:
   由于有些环境不一样,有时候第二个参数有可能为空,所以可以使用第三个参数
    因此在解析前,先调用一下看哪个参数能用,第4个参数是这个节点的属性。
	这里我们不需要这个节点,所以从<book>这个节点开始,也就是图中1的位置,
	当读入时,调用startElement(....)方法,
	由于只有一个属性id,可以通过attributes.getValue(0)来得到,然后在图中标明2的地方会调用characters(char[] ch, int start, int length)方法,不要以为那里是空白,
	Sax解析器可不那么认为,Sax解析器会把它认为是一个TextNode
	但是这个空白不是我们想要的数据,我们是想要<name>节点下的文本信息。这就要定义一个记录当上一节点的名称的TAG,在characters(.....)方法中,
	判断当前节点是不是name,是再取值,才能取到maomao
总结:  
   使用SAX解析XML采用的是从上而下的基于事件驱动的解析方式
   解析过程中会视情况自动调用startDocument()、startElement()、characters()、endElement()、endDocument()等相关的方法
1. startDocument()方法只会在文档开始解析的时候被调用,每次解析只会调用一次。
2. startElement()方法每次在开始解析一个元素,即遇到元素标签开始的时候都会调用。
3. characters()方法也是在每次解析到元素标签携带的内容时都会调用,即使该元素标签的内容为空或换行。而且如果元素内嵌套元素,在父元素结束标签前, characters()方法会再次被调用,此处需要注意。
4. endElement()方法每次在结束解析一个元素,即遇到元素标签结束的时候都会调用。
5. endDocument() startDocument()方法只会在文档解析结束的时候被调用,每次解析只会调用一次
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java如何使用SAX(Simple API for XML)解析XML呢? 的相关文章

  • Gradle 构建错误:无法从 https://repo1.maven.org/maven2/io/fabric/tools/gradle/maven-metadata.xml 加载 Maven 元数据

    我在 Android studio 中遇到 gradle 构建错误 如下所示 Error A problem occurred configuring project MyApp Could not resolve all dependen
  • 在 Java 中克隆对象 [3 个问题]

    这样做会调用Asub的clone方法吗 或者Asub深度克隆是否正确 如果没有的话 有没有办法通过这种方法对Asub进行深度克隆呢 abstract class Top extends TopMost protected Object cl
  • 序列的排列?

    我有具体数量的数字 现在我想以某种方式显示这个序列的所有可能的排列 例如 如果数字数量为3 我想显示 0 0 0 0 0 1 0 0 2 0 1 0 0 1 1 0 1 2 0 2 0 0 2 1 0 2 2 1 0 0 1 0 1 1 0
  • 如何通过 javaconfig 使用 SchedulerFactoryBean.schedulerContextAsMap

    我使用 Spring 4 0 并将项目从 xml 移至 java config 除了访问 Service scheduleService 带注释的类来自QuartzJobBean executeInternal 我必须让它工作的 xml 位
  • Java 枚举与创建位掩码和检查权限的混淆

    我想将此 c 权限模块移植到 java 但是当我无法将数值保存在数据库中然后将其转换为枚举表示形式时 我很困惑如何执行此操作 在 C 中 我创建一个如下所示的枚举 public enum ArticlePermission CanRead
  • .properties 中的通配符

    是否存在任何方法 我可以将通配符添加到属性文件中 并且具有所有含义 例如a b c d lalalala 或为所有以结尾的内容设置一个正则表达式a b c anything 普通的 Java 属性文件无法处理这个问题 不 请记住 它实际上是
  • 如何使用assertEquals 和 Epsilon 在 JUnit 中断言两个双精度数?

    不推荐使用双打的assertEquals 我发现应该使用带有Epsilon的形式 这是因为双打不可能100 严格 但无论如何我需要比较两个双打 预期结果和实际结果 但我不知道该怎么做 目前我的测试如下 Test public void te
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 在 Jar 文件中运行 ANT build.xml 文件

    我需要使用存储在 jar 文件中的 build xml 文件运行 ANT 构建 该 jar 文件在类路径中可用 是否可以在不分解 jar 文件并将 build xml 保存到本地目录的情况下做到这一点 如果是的话我该怎么办呢 Update
  • 将流转换为 IntStream

    我有一种感觉 我在这里错过了一些东西 我发现自己做了以下事情 private static int getHighestValue Map
  • 检测并缩短字符串中的所有网址

    假设我有一条字符串消息 您应该将 file zip 上传到http google com extremelylonglink zip http google com extremelylonglink zip not https stack
  • 内部类的构造函数引用在运行时失败并出现VerifyError

    我正在使用 lambda 为内部类构造函数创建供应商ctx gt new SpectatorSwitcher ctx IntelliJ建议我将其更改为SpectatorSwitcher new反而 SpectatorSwitcher 是我正
  • volatile、final 和synchronized 安全发布的区别

    给定一个带有变量 x 的 A 类 变量 x 在类构造函数中设置 A x 77 我们想将 x 发布到其他线程 考虑以下 3 种变量 x 线程安全 发布的情况 1 x is final 2 x is volatile 3 x 设定为同步块 sy
  • 如何在用户输入数据后重新运行java代码

    嘿 我有一个基本的java 应用程序 显示人们是成年人还是青少年等 我从java开始 在用户输入年龄和字符串后我找不到如何制作它它们被归类为 我希望它重新运行整个过程 以便其他人可以尝试 的节目 我一直在考虑做一个循环 但这对我来说没有用
  • tomcat 中受密码保护的应用程序

    我正在使用 JSP Servlet 开发一个Web应用程序 并且我使用了Tomcat 7 0 33 as a web container 所以我的要求是tomcat中的每个应用程序都会password像受保护的manager applica
  • 如何使用 jUnit 将测试用例添加到套件中?

    我有 2 个测试类 都扩展了TestCase 每个类都包含一堆针对我的程序运行的单独测试 如何将这两个类 以及它们拥有的所有测试 作为同一套件的一部分执行 我正在使用 jUnit 4 8 在 jUnit4 中你有这样的东西 RunWith
  • Opencv Java 灰度

    我编写了以下程序 尝试从彩色转换为灰度 Mat newImage Imgcodecs imread q1 jpg Mat image new Mat new Size newImage cols newImage rows CvType C
  • 如何使用mockito模拟构建器

    我有一个建造者 class Builder private String name private String address public Builder setName String name this name name retur
  • 包 javax.el 不存在

    我正在使用 jre6 eclipse 并导入 javax el 错误 包 javax el 不存在 javac 导入 javax el 过来 这不应该是java的一部分吗 谁能告诉我为什么会这样 谢谢 米 EL 统一表达语言 是 Java
  • 使用反射覆盖最终静态字段是否有限制?

    在我的一些单元测试中 我在最终静态字段上的反射中遇到了奇怪的行为 下面是说明我的问题的示例 我有一个基本的 Singleton 类 其中包含一个 Integer public class BasicHolder private static

随机推荐

  • J-002 Jetson电路设计之电源设计--NANO && XAVIER NX

    Jetson电源设计 1 电源说明 1 1 电源和系统引脚描述 1 2 电源控制框图详情 2 上电的时许 2 1 框图分析 2 2 上电时序 3 GND引脚 1 电源说明 Jetson NANO和XAVIER NX核心板的电源为DC 5V
  • 白盒测试之静态检查

    态检查一般是检查编码标准规范 错误列表 编码规范往往团队 会根据自己的经验和风格进行设置一些规范 现在很多IDE工具都会 在编辑代码的时候实时的提醒是否符合代码风格 错误列表 一般 是代码潜在的bug 由于某种代码写法虽然没有语法错误 但是
  • 现在有多个异步操作ajax请求,我们需要当所有异步请求都成功的时候,执行后续操作

    1 场景 现在有多个异步操作ajax请求 我们需要当所有异步请求都成功的时候 执行后续操作 2 方法 方法一 通常的讲 我们可以设置一个flag变量 然后在各自的ajax的成功回调内去维护这个变量数量 当满足条件时 我们来触发后续函数 方法
  • stat函数(stat、fstat、lstat)

    include
  • 基于STM32的录音与播音

    基于STM32的录音与播音 设计方案 本设计通过STM32的内置ADC加一个麦克风和放大电路 可以在网上买模块 实现音频的采集 然后存放在SD卡中 这里可以参考我之前的博客FATFS文件系统 然后再读取SD卡里存放的数据通过单片机的内置DA
  • [WPF]WPF Data Virtualization和UI Virtualization

    这篇博客将介绍WPF中的虚拟化技术 1 Data Virtualization 通常情况下我们说数据虚拟化是指数据源没有完全加载 仅加载当前需要显示的数据呈现给用户 这种场景会让我们想到数据分页显示 当需要特定页面的数据时 根据页数请求相应
  • noip2013提高组初赛(答案+选择题题目+个人分析)

    一 单项选择题 共 15 题 每题 1 5 分 共计 22 5 分 每题有且仅有一个正确 选项 1 一个 32 位整型变量占用 个字节 A 4 B 8 C 32 D 128 A 1字节 8位 1byte 8bit 2 二进制数 11 01
  • Linux 搜索文件和文件夹的 4 种简单方法

    英文 Prakash Subramanian 翻译 Linux中国 geekpi linux cn article 10362 1 html Linux 管理员一天都不能离开搜索文件 因为这是他们的日常活动 了解一些搜索的东西是不错的 因为
  • jquery的ajax数据显示不出来,jQuery的Ajax请求确实在HTML元素不显示数据

    当我运行在循环Ajax请求 成功AJAX不显示返回的数据 这里是代码 jQuery的Ajax请求确实在HTML元素不显示数据 url siteAdmin statistics queriesAjax php siteAdmin statis
  • 5.3中断系统中的设备树——中断号的演变与irq_domain

    通过上一节我们知道 在内核中有一个irq desc数组 数组里面的每一项对应一个中断 数组的下标就是对应中断的虚拟中断号 virq 假设只有一个中断控制器 有32个中断 那么中断和irq desc数组可以一一对应 每一个数组项对应一个中断
  • 通用LOG封装

    ifndef LOG H define LOG H if defined cplusplus extern C endif include stm32l0xx hal h include
  • 区块链的物演天论

    自本周一以来 黄金白银遭受了猛烈的下跌 就像我之前文章表述的 当投资者开始担心美股的涨幅的时候 市场就会出现动摇 进而影响了黄金与白银的下跌 其实 从9月初开始 欧美股市已经遭遇了猛烈抛售 美股已经距离9月初高点跌去10 以上 除了美股以外
  • [632]mysql安装(centos7

    文章目录 centos7 tar包安装 MySQL5 7 一 CentOS7 4系统自带mariadb 二 检查mysql是否存在 三 查看用户和组是否存在 四 下载mysql的tar包 五 上传第四步下载的mysql TAR包到 六 更改
  • pycharm连接mysql8.0报错

    为了pycharm方便远程连接 偷懒未创建用户 直接修改root进行远程连接 但是修改完成之后 在使用pycharm连接数据库出现报错 RuntimeError cryptography is required for sha256 pas
  • Xcode error: Cannot link directly with dylib/framework, your binary is not an allowed client of /

    文章目录 编译报错 Trust App 编译报错 Mac 机子 数据线连接 iPhone13 通过 Appium 里的 appium webdriveragent WebDriverAgent xcodeproj 工程 来编译可以在 iPh
  • python实验(3)

    按公式s 12 22 32 n2 求累计加和 s不超过1000的最大项数n 程序运行结果如下所示 x 1 count 0 print x gt sum for x in range 0 14 count x x print str x gt
  • golang笔记-区块链密码学01

    文章目录 pbkdf2 Key 生成秘钥函数 HMAC 生成摘要算法 PrivKeyFromBytes 创建私钥 公钥对 pbkdf2 Key 生成秘钥函数 PBKDF2 Password Based Key Derivation Func
  • markdown图片显示

    目录 markdown中图片显示 图片显示方法 图片显示的格式 注意 绝对路径与相对路径 绝对路径 相对路径 markdown中图片显示 图片显示方法 网页图片 先将图片上传到服务器 可以支持多用户查看分享之后不会出现图片无法加载的情况 本
  • SaaS软件能保证数据安全吗?

    SaaS软件能保证数据安全吗 本文将要尝试从各个方面尽可能客观的去阐述这个问题 而不是简单自嗨式的说简道云平台如何保障数据安全 建议先收藏起来慢慢品 01 SaaS安全到底是什么 定义解读 本文所用SaaS平台 gt gt gt gt ht
  • Java如何使用SAX(Simple API for XML)解析XML呢?

    转自 Java如何使用SAX Simple API for XML 解析XML呢 下文讲述使用SAX解析xml文档的方法分享 如下所示 SAX简介 SAX用于加载文档到内存中 它是采用事件驱动的API Observer模式 他按照xml文件