Java中Xml解析详解 DOM、SAX、JDOM、DOM4J

Java中四种XML解析方式详解与实战(DOM4J、JDOM、DOM、SAX) DOM4J作为一款专为Java平台设计的开源XML解析库,自发布以来便因其卓越的性能表现和优雅的API设计而广受开发者青睐。它采用混合式解析策略——在保留DOM模型完整树结构的同时,借鉴SAX的轻量级事件驱动机制,在内存占用与处理速度之间实现了良好平衡。这种设计理念使其既适用于需要频繁修改和随机访问的小型配置文件,也适合处理中等规模的数据交换文档。与其他XML处理框架相比,DOM4J最突出的优势在于其对XPath的深度集成。 阅读详情

1.1 什么是XML

一种表示结构化信息的标准方法,以使计算机能够方便地使用此类信息,并且人们可以非常方便地编写和理解这些信息。XML 是 eXtensible Markup Language(可扩展标记语言)的缩写。www.w3.org/XML/ 上提供了 XML 标准。XML 提供了一种简便的标准方法对数据进行分类,以使其更易于读取、访问以及处理。XML 使用类似于 HTML 的树结构和标签结构.


例如:
<?xml version="1.0"?>
<myfile>
<title>XML Quick Start</title>
<author>zhangsan</author>
<email>zhangsan@hotmail.com</email>
<date>2013-1-1</date>
</myfile>

大部分标签都是我们自己定义的
XML产生的目标:
处理XML文档的程序应该容易编写
在XML中,要求可供选择的特性数量保持绝对的少,更理想一点一个也没有
XML文档应当是可读性强和条理清晰的
XML的设计应当是正规并且简洁的
XML文档应该容易创建
在XML的结构中应该简洁、精练
在Internet上XML应该是直接可以使用的
XML应该支持各种各样的应用
Java与xml是一种完美的组合,Java平台是一种跨平台的编程环境 ,XML是一种跨平台的数据格式 与其他语言相比,Java平台提供了更好的XML支持

1.2 Xml的作用和优点:

主要作用:
存储数据:最基本的办法是采用io流读取
配置文件(用得最多)
XML与Access,Oracle和SQL Server等数据库不同,数据库提供了更强有力的数据存储和分析能力,例如:数据索引、排序、查找、相关一致性等,XML仅仅是展示数据。事实上XML与其他数据表现形式最大的不同是:他极其简单。
主要特点:
支持设计与特定领域相关的标记
自描述数据
不需要借助于其它的工具就可以理解XML中数据的含义,是因为XML中对数据进行了自描述,这保证了只要XML文件本身不被破坏就可以理解所包含数据的含义。同时,XML有很好的规格文档,保证了XML的语义不被误解。
应用间自由交换数据
webservice
结构化和集成的数据


1.3 XML 文档类型:

无效文档:
没有遵守 XML 规范定义的语法规则。
如果开发人员已经在 DTD 或模式中定义了文档能够包含什么,而某个文档没有遵守在其 DTD 或模式中定义的规则
有效文档:既遵守 XML 语法规则也遵守在其 DTD 或模式中定义的规则。 
格式良好(well-formed)的文档:遵守 XML 语法,但没有 DTD 或模式。

1.4 XML 声明 

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
建议使用 XML 声明,但它不是必需的。如有应该在文档开始位置。
声明最多可以包含三个 名称-值 对。
version 是使用的 XML 版本;目前该值必须是 1.0。
encoding 是该文档所使用的字符集。该声明中引用的 ISO-8859-1。如没有指定 encoding,XML 解析器会假定字符在 UTF-8 字符集中,这个字符集是一个几乎支持世界上所有语言的字符和象形文字的 Unicode 标准。
standalone(可以是 yes 或 no),本是独立的意思,定义了是否可以在不读取任何其它文件的情况下处理该文档。例如,如果 XML 文档没有引用任何其它文件,可指定 standalone="yes"。如果 XML 文档引用其它描述该文档可以包含什么的文件可指定 standalone="no",standalone="no" 是缺省的。


1.5 XML 文档中的转义字符

为解决xml文档中各种标记符号的歧义问题,xml提供了如下转义字符:
&lt; 代表小于符号 
&gt; 代表大于符号 
&quot; 代表一个双引号 
&apos; 代表一个单引号(或撇号) 
&amp; 代表一个“与”符号&。

为了避免 XML 解析错误,我们应该使用 &lt; 来替代 <,使用 &amp; 替代 &。但是假设你需要在 XML 文档里写一段内容,里面包含了很多 < 或者 &,要将所有 < 或者 & 转换成实体引用是很讨厌的事情。
这时候,你可以使用 CDATA 区 (CDATA section)。在 CDATA 区里,你可以不必使用实体引用,因为 XML 解析器不会解析 CDATA 区内的内容。
CDATA 区 (CDATA section) 以 <![CDATA[ 开始,以 ]]> 结束。 示例如下:

<mycode> This is a html page
<![CDATA[
<html>
	<head>
		<title>呵呵</title>
	</head>
	<body>
		I like 
	</body>
</html>
]]></mycode>

注意:在 CDATA 区内,不能出现 ]]>


1.6 XML语法规则

1、 是否有DTD文件
如果文档是一个"有效的XML文档",那么文档一定要有相应DTD文件,并且严格遵守DTD文件制定的规范。DTD为英文Document Type Definition,中文意思为“文档类型定义”,用于定义这个文档的具体类型,不通场合的xml类型不一样,具体用那一种,要通过DTD定义,所以使用时要指明相应的DTD文件。 

DTD的作用: 

一方面它帮助你编写合法的代码 ,另一方面它让浏览器正确地显示器代码。

DTD文件的声明语句紧跟在XML声明语句后面,格式如下:
<!DOCTYPE type-of-doc SYSTEM/PUBLIC "dtd-name">

其中:

"!DOCTYPE"是指你要定义一个DOCTYPE;
 "type-of-doc"是文档类型的名称,由你自己定义;
 "SYSTEM/PUBLIC"这两个参数只用其一。SYSTEM是指文档使用的私有DTD文件的网址,而PUBLIC则指文档调用一个公用的DTD文件的网址。
 "dtd-name" 就是DTD文件的网址和名称。所有DTD文件的后缀名为".dtd"。


例如用上面的例子,可写成这样:

<?xml version="1.0" standalone="no" encoding="UTF-8"?>

<!DOCTYPE filelist SYSTEM "filelist.dtd">


上面的声明表示:
该xml文件版本是1.0,引用了其他文件,文档字符编码是UTF-8
DTD文档类型名称是filelist,使用的是私有DTD文件的网址,DTD文件为filelist.dtd


2、区分大小写(case-sensitive)

在XML文档中,大小写是有区别的。<P>和<p>是不同的标识。注意在写元素时,前后标识大小写要保持一样。例如:<Author>ajie</Author>,写成<Author>ajie</author>是错误的。


3、属性值

在XML中则规定,所有属性值必须加引号(可以是单引号,也可以是双引号),否则将被视为错误。

 属性名的第一个字母必须以字母或下划线开头

 在同一个开始标记里,一个特殊的属性名只能出现一次


4、所有的标识必须有相应的结束标识

在XML中规定,所有标识必须成对出现,有一个开始标识,就必须有一个结束标识。


5、所有的空标识也必须被关闭

空标识就是标识对之间没有内容的标识。在XML中,规定所有的标识必须有结束标识,针对这样的空标识,XML中处理的方法是在原标识最后加“/”。例如:<br>应写为<br/>;


1.7 XML解析技术(XML常用作作为数据存储格式)

1、DOM(Document object model)
解析器采用了基于树状的模型,侧重结果
优点:

层次清晰,便于存取其中的节点。

缺点:

DOM 构建整个文档驻留内存的树。如果文档很大,就会要求有极大的内存。

 DOM 创建表示原始文档中每个东西的对象,包括元素、文本、属性和空格。如果您只需关注原始文档的一小部分,那么创建那些永远不被使用的对象是极其浪费的。

 DOM 解析器必须在您的代码取得控制权之前读取整个文档。对于非常大的文档,这会引起显著的延迟。

DOM 解析器把 XML 文档转化为一个包含其内容的树,并可以对树进行遍历。然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用 DOM 解析器的时候需要处理整个 XML 文档,所以对性能和内存的要求比较高,尤其是遇到很大的 XML 文件的时候。由于它的遍历能力,DOM 解析器常用于 XML 文档需要频繁的改变的服务中。


2、SAX
解析器采用了基于事件的模型,侧重过程
优点:

快速、适合大文件。

缺点: 

编程较难,仅用于串行存取,由于应用程序不以任何方式存储数据,所以,使用 SAX 时,不可能对数据进行更改。

SAX(Simple API for XML) 不是某个官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。SAX 解析器采用了基于事件的模型,它在解析 XML 文档的时候可以触发一系列的事件,当发现给定的tag(标签)的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。

由于应用程序简单地检查经过其的数据,所以不需要将数据存储在内存里。当遇到大文档时,这是一个突出的优势。SAX 对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX 这种扩展能力得到了更好的体现。但用 SAX 解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。


选择 DOM 还是 SAX,这取决于几个因素:

应用程序的目的:如果必须对数据进行更改,并且作为 XML 将它输出,则在大多数情况下,使用 DOM。

 数据的数量:对于大文件,SAX 是更好的选择。 

 将如何使用数据:如果实际上只使用一小部分数据,则使用 SAX 将数据抽取到应用程序中,这种方法更好些。

 需要速度:通常,SAX 实现比 DOM 实现快。


3、JDOM

注意JDOM的J是Java的意思,决不是DOM扩展,虽然名字差不多,但两者平行的关系。与DOM主要有两方面不同:

首先,JDOM仅使用具体类而不使用接口。这在某些方面简化了API,但是也限制了灵活性。

第二,API大量使用了Collections类,简化了那些已经熟悉这些类的Java开发者的使用。是一个开源项目,它基于树型结构,利用纯JAVA的技术对XML文档实现解析、生成、序列化以及多种操作。JDOM的目的是成为Java特定文档模型,它简化与XML的交互并且比使用DOM实现更快 JDOM 自身不包含解析器。它通常使用 SAX2 解析器来解析和验证输入 XML 文档(尽管它还可以将以前构造的 DOM 表示作为输入)。


4、DOM4J

具有性能优异、功能强大和使用便捷的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM也在用DOM4J。 目前许多开源项目中大量采用DOM4J,例如Hibernate也用DOM4J来读取XML配置文件。


1.8 用DOM4J技术解析XML

1、 简介

 dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的。Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。


2、 DOM4J的API文档

从网上可以下载DOM4J的API帮助文档、jar包(如dom4j-1.6.1.jar)、开源代码。其帮助文档首页如下: 

Home是首页,FAQ是常见问题,Quick start是快速入门,主要说明dom4j的基本使用方法,并列举了一写简单的例子。包括如何得到一个xml文档对应的Document对象,(在Java编程环境中模拟的一个文档),通过迭代器(Iterator)遍历xml树,快速循环,创建XML文档,把一个document写到文件中等。Javadoc(1.6.1)就是对应的dom4j对应的类似Java JDK帮助文档一样文档。里面特别常用的接口以斜体方式显示。如Node、Document、Elemet等。


3、 dom4j中常用的接口概述

它的主要接口都在org.dom4j这个包里定义:

Attribute 接口定义了XML的属性 

 Branch接口为能够包含子节点的节点如XML元素(Element)和文档(Docuemnts)定义了一个公共的行为, 

 CDATA接口定义了XML CDATA 区域 ,次区域的大于小于等符号不会被当做标签的符号来读取。

 CharacterData接口是一个标识借口,标识基于字符的节点。如CDATA,Comment, Text. 

 Comment接口定义了XML注释的行为 

 Document 定义了XML文档 

 DocumentType接口定义XML DOCTYPE声明 

 Element Element定义XML 元素 

 ElementHandler接口定义了 Element 对象的处理器 

 ElementPath 被 ElementHandler 使用,用于取得当前正在处理的路径层次信息 

 Entity接口定义xml实体:XML entity 

 Node接口为所有的dom4j中XML节点定义了多态行为 

 NodeFilter接口定义了在dom4j节点中产生的一个滤镜或谓词的行为(predicate) 

 ProcessingInstruction接口定义 XML 处理指令. 

 Text接口定义XML 文本节点. 

 Visitor接口用于实现Visitor模式. 

 XPath接口在分析一个字符串后会提供一个XPath 表达式 


常用接口的继承关系:

java.lang.Cloneable

Node

DocumentType

Attribute

ProcessingInstruction

Entity

Branch

Document

Element

CharacterData

CDATA

Text

Comment

可见,上面关系中,大多都是Node的子节点,这些节点都来自java.org.dom4包中。


4、 Dom4j常用接口、类说明
1) Node接口

asXML():隶属于Node类,用于将XML转换为String

 public Node selectSingleNode(String xpathExpression)可以通过xpath路径返回一个节点。若xpathExpression为"/users/user[id='108']",则得到的是user节点,它有一个子元素id,标签id的值为108.若xpathExpression为"/users/user[@firstname='liu']",则会得到一个user节点,它有个属性是firstname,属性值为liu。

public List selectNodes(String xpathExpression)可以返回所有xpath路径指定的节点


2) SAXReader接口

此接口通过SAX解析事件创建一个DOM4J的SAXReader对象树。常用其无参构造方法SAXReader()。

 public Document read(InputStream in)此方法可以读取一个输入流in,返回一个Java环境下文档Document类型的对象。SAXReader的read方法是重载的,可以从InputStream, File, Url等多种不同的源来读取。得到的Document对象就带表了整个XML。读取的字符编码是按照XML文件头定义的编码来转换。如果遇到乱码问题,注意要把各处的编码名称保持一致即可。

3) Document接口

此接口是Node的子接口,用于定义一个XML文档,没有自己的构造方法,有两种方法得到Document对象:一是从SAXReader的read方法读流得到,二是由DocumentHelper类的静态方法createDocument得到。

 public Element getRootElement() 此方法可以得到这个Document的根元素,也就是树的根。

 public Element addElement(String name)此方法是从Document的父类Node那里继承而来的, 可以给Document添加一个名为name元素,并返回这个元素。

 public void add(Element element)此方法也是从Node那里继承而来,可以添加一个元素到该document的分支上。如果传进来的元素已经有了父节点,就会抛出非法异常。


4) Element接口

此接口是Node、Branch的子接口,用于定义一个XML元素,也就是树的节点,一个元素可以设置命名空间,属性,子节点和文本内容。

 public Element element(String name) 此方法可以得到该元素下面名字为name的子元素

 public List elements() 此方法可以得到一个存储该元素下面所有元素的List表。

 public String getText() 此方法可以返回该元素的文本内容,如果内容为空则返回一个空字符串而不是null。

 public String getTextTrim() 返回该元素所含有的text内容,其中连续的空格被转化为单个空格,该方法不会返回null

 public String attributeValue(String name) 此方法可以得到该元素名为name的属性的值,如果xml文档中没有指明该属性,就返回其默认值。

 public String attributeValue(String name,String defaultValue)该方法返回该元素名为name属性的值,如果xml文档中没有指明,就返回传给此方法的dafaultValue,这可能并不是该属性的默认值。

 public Element addAttribute(String name,String value)此方法可以给该元素名为name的属性设置值,并覆盖该属性先前的值。返回该元素。 

 部分其他方法简介

MethodComment

getQName()元素的QName对象

getNamespace()元素所属的Namespace对象

getNamespacePrefix()元素所属的Namespace对象的prefix

getNamespaceURI()元素所属的Namespace对象的URI

getName()获取该元素的local name

getQualifiedName()元素的qualified name

attributeIterator()元素属性的iterator,其中每个元素都是Attribute对象

attributeValue()元素的某个指定属性所含的值

elementIterator()元素的子元素的迭代器Iterator,其中每个元素都是Element对象

element()元素的某个指定(qualified name或者local name)的子元素

elementText()元素的某个指定(qualified name或者local name)的子元素中的text信息

getParent元素的父元素

getPath()元素的XPath表达式,其中父元素的qualified name和子元素的qualified name之间使用"/"分隔

isTextOnly()是否该元素只含有text或是空元素

detach() 移除自己

isRootElement()是否该元素是XML树的根节点

selectNodes(String xpathExpression)通过XPATH获取节点。

selectSingleNode(String xpathExpression)通过XPATH获取一个节点。

getDocument()作为一个Document返回


5) OutputFormat类

问题:把做好的xml文档直接用流输出,输出的方式默认为紧凑的,才用UTF-8编码,遇到中文字符就会显示为乱码。如何用很清晰的缩进的格式显示呢。

 说明:此类位于java.org.dom4j.io包中,用于格式化XML文档的输出。

此类的使用方式是将此类的对象作为参数传递给XMLWriter类的构造方法,从而构建一个XML输出流类,调用其write方法进行输出。

 public static OutputFormat createPrettyPrint()此静态方法不是OutputFormat的构造方法,但该方法可以创建一个设定好XML输出格式的OutputFormat对象。此默认格式就是,元素标签之间换行,并且子元素与父元素间产生2个空格的缩进,且换行、缩进中空的部分都是空白。

 public void setIndent(String indent) 该方法可以设置该类对象的XML文档输出时,子元素与父元素间缩进填充的字符串indent。字符串indent将会显示在XML文档子元素与父元素间缩进的位置。

 public void setEncoding(String encoding)此方法可以设定输出的XML文档的编码方式,如果是GBK就可正确显示文档的中文信息。


6) XMLWriter类

此类是dom4j.io中的类,可以得到一个dom4j树,把他按xml文件格式的流。其有参构造方法可以接受一个设定好xml文档格式的OutputFormat,并按照这个OutputFormat给定格式输出xml文档。写入文件后,要调用此类的flush方法刷新缓冲区,在关闭流。

 public XMLWriter(OutputStream out, OutputFormat format)

给构造方法,就收一个输出流对象和一个OutputForemat对象。out可以指定XMLWriter输出XML文档的地方,format指定输出格式。

 write方法

此方法进行了多次重载,可以写Document、Element、String等等。


7) DocumentHelper

createDocument():创建一个Document对象

 parseText(String text):解析给定Xml的文本,生成Document对象 


5、 用DOM4解析技术操作xml文档

1) 几种存储方式:

普通txt文件------存取不便

 数据库 -----------没必要

 技术 -------------结构清晰,层次明了


Xml与数据库中表的关系:

根元素-----表名

 子元素-----记录

 子元素中的子元素---------字段 


2) 生成xml文档:

得到文件输出流:新建File对象,创建FileWriter输出流

 设置生成文档格式:创建OutputFromat对象设置

 创建输出流:创建XMLWriter,构造方法得到输出流、设定的格式

 写文件到磁盘:把已有的Document对象通过XMLWriter的write方法写入磁盘

 刷新、关闭流


3) 获取xml文档:

找到文件:通过磁盘xml文件,new一个File对象

 打开文件:通过得到的文件对象创建一个InputStream

 把InputStream变成树:创建一个SAXReader对象,通过其read方法读文件对象或输入流对象得到一个Document对象


4) 查询xml文档的叶子节点

找树根:Document的getRootElement方法可以得到SAXReader创建的树的类型为Element的根节点。

 找树枝:Element接口中的elements()可以找到该元素下的所有节点

 找树叶:用element方法可以找到指定名称的子节点

 关闭流


Xml path简称xpath
问题:查找过程浪费时间在一些中间节点,如果中间节点过多则性能下降。
定义:由xml中的节点或者属性构成的序列。

XPath是用来搜索和查询XML文档,以得到与给定标准相匹配的节点列表的语言。它已经被W3C标准化了。一个XPath语言的表达式可详细说明要匹配的位置和模式。将布尔运算符、字符串运算符和算术运算符应用到XPath语言的表达式中,能够建立极其复杂的查询.

作用:根据条件(某个节点或者属性)快速定位某个节点。
关系:
Users----user-----id

/users/user[id='108']

借助子节点的值来定位父节点

条件是id的值

定位的节点是user

/users/user[@firstname='liu']

借助节点属性值来定位所在的节点。


XPath语言的特性

能找到当前节点的所有子节点

 能找到具有特定标志的当前上下文节点的所有祖先节点

 能找到具有特定标志的当前节点的最后一个子元素

 根据一个给定属性的元素的当前上下文节点找到第n个元素

 能找到具有<tag1>或<tag2>标志的第一个子元素

 能找到不具有某个属性的元素的所有子节点

 能找到所有数字元素子节点的总和

 能找到所有子节点的数量


待解析的xml:

<?xml version="1.0" encoding="UTF-8"?>
<students count="1"> 
   <student aa="abc"> 
        <sid>119</sid>  
        <sname>刘晓东</sname>  
        <major>computer</major>
        <password>34567</password>  
        <birth>1997-08-01</birth>  
        <address>USA</address>  
        <gender>m</gender> 
    </student>
    <student firstname="liu"> 
        <sid>121</sid>  
        <sname>晓东</sname>  
        <major>computer</major>
        <password>34567</password>  
        <birth>1997-08-01</birth>  
        <address>USA</address>  
        <gender>m</gender> 
    </student>
     <student> 
        <sid>120</sid>  
        <sname>刘晓东</sname>
        <major>computer</major>  
        <password>34567</password>  
        <birth>1997-08-01</birth>  
        <address>USA</address>  
        <gender>m</gender> 
    </student> 
</students>



示例部分代码如下:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**对Document的一些操作都放在此类管理
 * 1.通过xml文件得到Document对象
 * 2.对已有的Document对象,把他按照我们的格式写到磁盘中
 */
public class DocumentManager {

	private static String fileName = "src/Users.xml";
	public static Document getDocument(){
		return getDocument(fileName);
	}
	public static Document getDocument(String fileName){
		try {		
			File file = new File(fileName);
			InputStream is = new FileInputStream(file);
			SAXReader reader = new SAXReader();
			Document document = reader.read(is);
			return document;
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return null;
	}
	
	public static void writeDocument(Document document){
		writeDocument(document,fileName);
	}
	public static void writeDocument(Document document,String filename){
		//1.set the format
		OutputFormat format = OutputFormat.createPrettyPrint();
		//2.set the indent to 4 white spaces.
		format.setIndent("    ");		
		try {			
			XMLWriter writer = new XMLWriter(new FileOutputStream(filename),format);			
			writer.write(document);	
			writer.flush();
			writer.close();			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
	
	public static void main(String[] args) {
		 getDocument();

	}

}


import java.sql.Date;

/**创建一个程序中实体对应xml中的信息,更加人性化,用户也更容易
 * 理解 当然这就需要xml中的东西与实体间进行转换,包含对象、操作等 
 * 1.创建一个用户类User,对应xml中的Student,用户的属性对应xml中Student所有子元素
 * 2.实体的各属性都要有set、get方法,以便设置、获取属性值
 * 3.尤其是对xml的文档的元素进行排序,如果用xml里面的元素排,在排的时候要把元素从他们的父节点上移除
 *   添加的时候还要设置被被添加的子元素的父节点为null,很是麻烦,用把Element转换成为User对象,排好了序
 *   再写到原来的xml文档,这样就简单很多。
 * 4.重写toString方法便于查看属性
 */
public class User {
	private Integer id = null;
	private String username =  null;
	private String password = null;
	private Date   birth = null;
	private String address = null;
	private String gender = null;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Date getBirth() {
		return birth;
	}
	public void setBirth(Date birth) {
		this.birth = birth;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	
	@Override
	public String toString(){
		return "id=" + id + "\tusername=" + username + "\tpassword=" + password
				+ "\tgender="+gender+"\taddress"+address+"\tbirth="+birth;
	}
}


import java.util.List;

/**创建一个接口,让人一步了然的看清有什么方法,做了写什么事,
 * 还可以实现接口
 */
public interface IUserDAO {
	public List<User> getAllUser();
	public User getUserByUsername(String username);
	public List<User> getUserListByUsername(String username);
	public List<User> getUserListByKeyword1(String keyword);
	public List<User> getUserListByKeyword2(String keyword);
	public boolean addUser(User user);
	public boolean addUserWithUniquePK(User user)throws UserExistsException;
	public boolean addUserWithAutoPK(User user);
	public boolean deleteUserByPK(int id);
	public boolean update(User user);
	public void sortUserList(List<User> userList);
	public void sortUserList(List<User> userList,boolean ascendable);
	public void testXPath1();
	public User getUserById(int id);
	public void sortById1();
	public void sortById2();
	public void sortById3();
	public void sortById4();
}


import java.sql.Date;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

public class UserDAO implements IUserDAO {
	/**
	 * 把一个Element对象转换成一个User对象 
	 * 1.得到Element各子元素存储的信息
	 * 2.把这些String类型的信息转换成相应的类型后赋值给User对象的属性
	 * 3.返回User对象
	 */
	private User getObjectFromElement(Element userElement) {
		String idStr = userElement.elementTextTrim("id");
		String username = userElement.elementTextTrim("username");
		String birthStr = userElement.elementTextTrim("birth");
		String gender = userElement.elementTextTrim("gender");
		String password = userElement.elementTextTrim("password");
		String address = userElement.elementTextTrim("address");

		Integer id = Integer.parseInt(idStr);
		// convert a string in the format "yyyy-mm-dd" into a Date type.
		Date birth = Date.valueOf(birthStr);
		User user = new User();
		user.setId(id);
		user.setUsername(username);
		user.setPassword(password);
		user.setBirth(birth);
		user.setAddress(address);
		user.setGender(gender);

		return user;
	}

	// 通过指定的用户名得到xml中第一个与指定用户名相同的用户对应的User对象
	public User getUserByUsername(String username) {
		try {
			Document document = DocumentManager.getDocument();
			Element usersElement = document.getRootElement();
			List<Element> userElementList = usersElement.elements();
			for (Element userElement : userElementList) {
				Element usernameElement = userElement.element("username");
				String _username = usernameElement.getText();
				if (username.equals(_username) == false) {
					continue;
				}
				return this.getObjectFromElement(userElement);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public List<User> getAllUser() {
		return null;
	}

	/**
	 * 通过指定的字符串查找到xml文件中用户名中包含此字符串的所有User对象
	 * 1.得到xml对应的Docuement对象,寻找到xml中所有的Student元素 
	 * 2.创建一个存储User对象的List列表
	 * 3.让Student的子元素也就是叶子节点存储的信息与我们想找的username比较
	 * 4.把匹配的转换成为User对象后添加到List中
	 * 5.返回这个List
	 */
	@Override
	public List<User> getUserListByUsername(String username) {
		Document document = DocumentManager.getDocument();
		Element usersElement = document.getRootElement();
		List<Element> userElementList = usersElement.elements();
		List<User> userList = new ArrayList<User>();
		// 创建一个ArrayList,这样的数组列表有序、可以重复、长度可变,
		// 用于存储我们找到的User对象
		for (Element userElement : userElementList) {
			String _username = userElement.elementTextTrim("username");
			if (_username.contains(username)) {
				User user = this.getObjectFromElement(userElement);
				userList.add(user);
			}
		}
		return userList;
	}

	/**
	 * 查询所有包含我们指定字符串内容信息的用户,并转换成User对象返回 
	 * 1.创建一个存储User对象的ArrayList
	 * 2.找到存有所有用户元素列表,循环找到各个user节点 
	 * 2.找到其字节点叶子节点,看他们的内容是否包含我们要查询的信息keywword
	 * 3.如果遇到任何一个叶子结点包含,就不再找这个user的后面元素了
	 * 4.满足条件的user节点转换成user对象,添加到List中
	 * 5.返回List
	 */
	public List<User> getUserListByKeyword1(String keyword) {
		Document document = DocumentManager.getDocument();
		Element usersElement = document.getRootElement();
		List<Element> userElementList = usersElement.elements();

		List<User> userList = new ArrayList<User>();
		for (Element userElement : userElementList) {
			String _username = userElement.elementTextTrim("username");
			if (_username.contains(keyword)) {
				User user = this.getObjectFromElement(userElement);
				userList.add(user);
				continue;
				// 如果这叶子节点包含我们想找的信息,就添加到List中,并终止本次循环
				// 不用在查这个user元素后面的子元素是否包含keyword
			}
			String password = userElement.elementTextTrim("password");
			if (password.contains(keyword)) {
				User user = this.getObjectFromElement(userElement);
				userList.add(user);
				continue;
			}
			String birth = userElement.elementTextTrim("birth");
			if (birth.contains(keyword)) {
				User user = this.getObjectFromElement(userElement);
				userList.add(user);
				continue;
			}
			String address = userElement.elementTextTrim("address");
			if (address.contains(keyword)) {
				User user = this.getObjectFromElement(userElement);
				userList.add(user);
				continue;
			}
			String gender = userElement.elementTextTrim("gender");
			if (gender.contains(keyword)) {
				User user = this.getObjectFromElement(userElement);
				userList.add(user);
				continue;
			}
		}
		return userList;
	}

	/**
	 * 与上面的getUserListByKeyword2功能一样
	 */
	public List<User> getUserListByKeyword2(String keyword) {
		Document document = DocumentManager.getDocument();
		Element usersElement = document.getRootElement();
		List<Element> userElementList = usersElement.elements();
		List<User> userList = new ArrayList<User>();
		for (Element userElement : userElementList) {
			List<Element> userSubelementList = userElement.elements();

			// traverse every sub-element of the user element.
			for (Element userSubelement : userSubelementList) {
				String elementValue = userSubelement.getTextTrim();
				if (elementValue.contains(keyword)) {
					// if the sub-element is located successfully,other
					// sub-element is not read any longer.
					User user = this.getObjectFromElement(userElement);
					userList.add(user);
					break;
					// 如果找到了user的某个子元素包含keyword,就跳出访问其
					// 子元素的这个循环,接着外层查找下个user的子节点是否包含
				}
			}
		}
		return userList;
	}

	/**
	 * 把一个User对象user,把它转换成为Element类型的user节点
	 * 1.创建名为user的Element对象
	 * 2.通过Element的addElement方法给user添加子元素 
	 * 3.设置子元素中的内容为User对象对应属性的内容
	 * 4.返回一个Element元素
	 */
	private Element getElementFromObject(User user) {
		Element userElement = DocumentHelper.createElement("user");
		// dom4j中的大多对象都不是构造方法生成的,而是用DcumentHelper来creat的
		// 包括文档、元素、属性、文本等都可以依次来生成
		userElement.addElement("id").setText(user.getId() + "");
		userElement.addElement("username").setText(user.getUsername());
		userElement.addElement("password").setText(user.getPassword());
		userElement.addElement("birth").setText(user.getBirth() + "");
		userElement.addElement("address").setText(user.getAddress());
		userElement.addElement("gender").setText(user.getGender());
		return userElement;
	}

	/**
	 * 添加User对象的用户user到XML文档中 
	 * 1.把User对象user转换成为Element类型的元素
	 * 2.得到指定xml文档的Document对象,找到要添加元素的节点 
	 * 3.通过addElement方法把要添加的元素填进去
	 * 4.更改计算user节点元素个数的count属性,每添加一个就加1 
	 * 5.把我们修改后的Document对象写到磁盘
	 */
	@Override
	public boolean addUser(User user) {
		Element userElement = this.getElementFromObject(user);
		Document document = DocumentManager.getDocument();
		Element usersElement = document.getRootElement();
		usersElement.add(userElement);
		this.setCountAttribute(usersElement, true);
		DocumentManager.writeDocument(document);
		return false;
	}

	/**
	 * 设置usersElement的计user数的属性count 
	 * 1.通过attributeValue方法得到该元素的指定属性的值 
	 * 2.转换成为整数类型
	 * 3.increment为false表示是增加元素,count就增加,反之减少
	 * 4.把count转换成字符串后通过addAtributte方法把设定好的属性添加到原节点中
	 */
	private void setCountAttribute(Element usersElement, boolean increment) {String countStr = usersElement.attributeValue("count");int count = 0;try {count = Integer.parseInt(countStr);} catch (NumberFormatException e) {
	// TODO Auto-generated 
	catch blocke.printStackTrace();}if (increment) {count++;} else {count--;}
	//addAttribute方法可以向元素中添加属性
	usersElement.addAttribute("count", count + "");
	}

	/**
	 * 添加id唯一的用户,一旦id相同就抛出异常。 
	 * 1.得到元素id 
	 * 2.坚持要插入元素的id是否已经存在 
	 * 3.如果不存在就添加元素,如果存在就抛出异常
	 * 这写操作是在转换成Element前做的,只是对User对象,这样更简便 *
	 */
	@Overridepublic
	boolean addUserWithUniquePK(User user) throws UserExistsException {
		Document document = DocumentManager.getDocument();
		if (this.findUserElementById(document, user.getId()) != null) {
			throw new UserExistsException("The user DOES EXIST!");
		}
		this.addUser(user);
		return false;
	}

	@Overridepublic
	boolean addUserWithAutoPK(User user) {
		// PK是primary key的缩写,主键的意思,这里就是id号
		// 自动设置用户id,找出现有id号最大的,让新加入的用户id号比最大的大一就可以了
		Document document = DocumentManager.getDocument();
		Element usersElement = document.getRootElement();
		List<Element> userElementList = usersElement.elements();
		int maxId = 0;
		for (Element userElement : userElementList) {
			String idStr = userElement.elementTextTrim("id");
			int id = 0;
			try {
				id = Integer.parseInt(idStr);
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
			if (maxId < id) {
				maxId = id;
			}
		}
		maxId++;
		user.setId(maxId);
		this.addUser(user);
		return false;
	}

	/** 通过id找到一个Document对象中的元素 */
	private Element findUserElementById(Document document, int id) {
		Element usersElement = document.getRootElement();
		List<Element> userElementList = usersElement.elements();
		for (Element userElement : userElementList) {
			// Step 2:
			String idStr = userElement.elementTextTrim("id");
			if (idStr.equals(id + "")) {
				return userElement;
			}
		}
		return null;
	}

	/**
	 * 删除指定id的节点  
	 * 1.通过id找到要删除的节点
	 *  2.找到要删除节点的父节点,可以用父接口中的getParent找到,在这里就是根节点
	 * 3.判断要删除的节点是否为空 
	 * 4.通过父节点,调用remove方法删除要删除的节点 
	 * 5.如果删除成功,就让计算user节点个数的减少
	 * 6.把修改过的Document对象写到原xml文件中 *
	 */
	public boolean deleteUserByPK(int id) {
		Document document = DocumentManager.getDocument();
		Element userElement = this.findUserElementById(document, id);
		if (userElement != null) {
			Element usersElement = document.getRootElement();
			if (usersElement.remove(userElement)) {
				// 执行remove方法的同时也做了判断条件,移除后才能设置计数的属性
				// alter the count attribute if succeeded in removing the
				element.this.setCountAttribute(usersElement, false);
			}
			// Step 4:re-write the document into the
			disc.DocumentManager.writeDocument(document);
		}
		return false;
	}

	/**
	 * 用户传入一个User对象,更新xml文档中对应元素的信息 
	 * 1.得到要更新的xml文档的document
	 * 2.由于id是唯一的,通过User对象中的id属性值,找到xml文档中对应id的元素
	 * 3.得到这个元素的父节点,可以用getParent方法,这里是根节点 
	 * 4.通过父节点调用remove方法移除原来的节点
	 * 5.把User对象转换成Element对象,添加到document中 
	 * 6.写更新后的document到xml文档
	 */
	@Overridepublic
	boolean update(User user) {
		Document document = DocumentManager.getDocument();
		Element userElement = this.findUserElementById(document, user.getId());
		Element usersElement = document.getRootElement();
		if (usersElement.remove(userElement)) {
			userElement = this.getElementFromObject(user);
			usersElement.add(userElement);
		}
		DocumentManager.writeDocument(document);
		return false;
	}

	/**
	 * 对一个存储User对象的UserList中的元素排序 
	 * 1.构建比较器对象,指定排序标准 
	 * 2.用Conections的sort方法排序
	 */
	@Overridepublic
	void sortUserList(List<User> userList, boolean ascendable) {
		// Step 1:make a sort
		standard.Comparator<User> userComparator = new UserComparator(
				ascendable);
		// Step 2:relate the sort standard to the sorted objects
		// 调用Collections的静态方法sort根据排序标准排序
		Collections.sort(userList, userComparator);
	}

	@Overridepublic
	void sortUserList(List<User> userList) {
		this.sortUserList(userList, true);
		// 默认排序顺序是升序
	}

	/**
	 * 通过xpath来快速查找 
	 * 1.设置xpath路径,是字符串的形式,XPath技术可以通过子元素名、自己属性名来获得节点, 
	 *    并可以进而找到其父节点、子节点、元素等
	 * 2.可以把xpath字符串路径传递给selectSingleNode、selectNodes方法,这两个方法来自Node,
	 * 来得到Node实例调用这两个方法的对象是说指XPath路径的父节点
	 */
	@Overridepublic
	void testXPath1() {
		// xpath可以根据条件(某个节点或者属性)快速定位某个节点。
		// locate user node whose sub-element id value is 121
		String xpath = "/users/user[id='121']";
		
		// 通过id值查找节点
		userDocument document = DocumentManager.getDocument();
		Node userElement = document.selectSingleNode(xpath);
		
		// selectSingleNode方法来自Node,可以通过xpath字符串路径得到一个Node实例
		// 此方法在此处返回的实例是Element对象,拥有子节点id为121的user节点
		System.out.println(this.getObjectFromElement((Element) userElement));
		System.out.println("username="
				+ ((Element) userElement).elementText("username"));
		String xpath = "/users/user[id='121']/username";
		Document document = DocumentManager.getDocument();
		Node userElement = document.selectSingleNode(xpath);
		
		// 此时selectSingleNode得到的是一个user节点的子元素username,
		// 该user节点有一个元素id,他的值为121
		System.out.println("username=" + ((Element) userElement).getTextTrim());
		String xpath = "/users/user[@firstname='liu']/birth";
		
		// 通过属性访问,这里的selectSingleNode方法得到的是user的一个子元素birth,
		// 这个user有个属性叫firstname,属性值为liu
		Element birthElement = (Element) DocumentManager.getDocument()
				.getRootElement().selectSingleNode(xpath);	
	}

	/**
	 * 通过id得到用户User对象
	 *  1.通过指定指定id建立可变的XPath字符串路径 
	 *  2.通过XPath路径得到xml文档中对应的元素
	 *  3.把找到的元素转换成为User对象类型返回
	 */
	@Overridepublic
	User getUserById(int id) {
		String xpath = "/users/user[id='" + id + "']";
		System.out.println("xpath=" + xpath);
		Element userElement = (Element) DocumentManager.getDocument()
				.selectSingleNode(xpath);
		return this.getObjectFromElement(userElement);
	}

	/**
	 * 让xml文档按照id进行排序 * 保留document,建新的根节点users 
	 * 1.得到原xml文档的document 
	 * 2.创建一个List
	 * 3.取原来xml文档的所有等待排序的user元素存在List中
	 * 4.把所有要排序的user元素从原根节点中移除来,这样他们才“自由”了,才可以进行排序,否则会抛出异常 
	 * 5.对List中所有元素排序 *
	 * 6.设置List中所有元素的父节点为null 
	 * 7.新建一个Element对象users
	 * 8.把排好序的List中的元素依次添加到users下面,添加一个节点为子元素时,必须确认其父元素为空
	 * 9.在document下面移除原来的根节点,设置users为根节点 
	 * 10.写document到xml文档
	 */
	public void sortById3() {
		List<Element> userElementList = rootElement.elements("user");
		// 把原来的所有用户存入List中
		Element newRootElement = DocumentHelper.createElement("users");
		
		// System.out.println("newRootElement父节点为"+newRootElement.getParent());
		// 重新创建一个users的节点
		for (Element userElement : userElementList) {
			rootElement.remove(userElement);
		}
		
		// 把原来根节点的所有内容从原来的根节点移除出去,这样这些节点才是自由的,才可以排序?
		List l = rootElement.elements();
		System.out
				.println("rootElement.elements() 有 " + rootElement.elements());
		Comparator userElementComparator = new UserElementComparator();
		Collections.sort(userElementList, userElementComparator);
		
		// sort方法根据Comparator中的compare方法的结果进行排序,Comparator是个比较器。
		// 此实现将指定列表转储到一个数组中,并对数组进行排序,在重置数组中相应位置每个元素的列表上进行迭代。
		for (Element userElement : userElementList) {
			System.out.println(userElement.elementTextTrim("id"));
		}
		for (Element userElement : userElementList) {
			// System.out.println("userElement父节点是:"+userElement.getParent());
			userElement.setParent(null);
			// System.out.println("userElement父节点变成了:"+userElement.getParent());
			// System.out.println();
			// 设置userElement的父节点为空newRootElement.add(userElement);
			// 在新的根节点上添加元素}newRootElement.setAttributeValue("count",
			// userElementList.size() + "");
			// 为新的根节点添加属性document.setRootElement(newRootElement);
			// setRootElement可以设置document的根节点DocumentManager.writeDocument(document);}}
		}
	}
}





dom4j-2.1.4.jar 立即下载

相关推荐

dom4j-jar包下载

 dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的。dom4j是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件,可以在SourceForge上找到它。在IBM developerWorks上面可以找到一篇文章,对主流的Java XML API进行的性能、功能和易用性的评测,dom4j无论在那个方面都是非常出色的。如今你可以看到越来越多的Java软件都在使用dom4j来读写XML,特别值得一提的是连Sun的JAXM也在用dom4j。这是必须使用的jar包, Hibernate用它来读写配置文件。

XML的四种解析器原理及性能分析比较

               XML的四种解析器原理及性能比较                                                     1: DOMDOM 是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准。DOM 是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要 加载整个文档和构造层次结构,然后才

1126

dom4j-2.1.1.jar

dom4j-2.1.1.jar

Dom4j SAXReader读取xml异常时占用文件,导致不能移动文件

使用SAXReader的read(File file)方法时,如果xml文件异常会导致文件被服务器占用不能移动文件,建议不使用read(File file)方法而使用read(FileInputStream fis)等流的方式读取文件,异常时关闭流,这样就不会造成流未关闭,文件被锁的现象了。(在服务器中运行时会锁住文件,main方法却不会)。 1、以下方式xml文件异常时会导致文件被锁

ablipan的专栏 4927

dom4J完整版jar下载

dom4J完整版jar下载

别再盲调PID了!手把手教你用VOFA+实时可视化电机速度曲线(附STM32F4源码)

本文详细介绍了如何使用VOFA+工具实现PID参数的可视化调试,帮助开发者从盲调转向精准调优。通过实时可视化电机速度曲线,结合STM32F4源码示例,展示了如何高效调试Kp、Ki、Kd参数,解决响应慢、超调等常见问题,大幅提升电机控制系统的性能。

weixin_28366475的博客 129

Java核心基础知识概述

本文深入解析Java六大核心基础模块:1)JVM实现跨平台的字节码机制与垃圾回收原理;2)面向对象三大特性的实现与常见陷阱;3)JMM内存模型与并发编程规则;4)Checked与Unchecked异常的设计哲学;5)集合框架的接口抽象与高效实现;6)泛型的类型擦除机制与解决方案。这些核心知识构成Java高级特性的基础,包括字节码执行、内存管理、并发控制等底层原理,以及面向对象、异常处理等编程范式,是掌握Java技术的必备基础。

huangpf_vcx 5031

立创开源:基于STM32F407的大疆M30T无人机PSDK机载开发板硬件设计与飞行控制实现

本文详细介绍了基于STM32F407微控制器为大疆M30T无人机设计PSDK机载开发板的完整流程。从关键的E-Port接口电路设计、电源保护,到STM32最小系统搭建,再到通过PSDK实现与无人机的通信及基础飞行控制,提供了从硬件到软件的全栈实战指南,助力开发者快速入门无人机负载开发。

weixin_35649491的博客 401

XML--04--解析-DOM4J 和 JDOM

DOM4J方式 dom4j是一个Java的第三方类库 XML API,类似于jdom,用来读写XML文件的。用于处理 XML、 XPath 和 XSLT,它基于 Java 平台,使用 Java 的集合框架,全面集成了 DOM,SAX 和 JAXP 对主流的Java XML API进行的性能、功能和易用性的评测,dom4j无论在那个方面都是非常出色的。如今你可以看到越来越多的Java软件都在使用dom4j来读写XML,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。 一、DO

时光里的博客 2801

蓝牙配对鉴权过程深度剖析:Just Works/Numeric Comparison/Passkey Entry/OOB 协议流程

当你新买的智能手表与手机配对时,是否遇到过这样的情况:有时只需在手机上点击 "确认" 即可完成配对,有时却需要在手表上输入手机显示的 6 位数字,而连接车载蓝牙时可能又需要输入固定密码?这些差异背后,是蓝牙配对鉴权机制在默默工作。蓝牙配对鉴权是设备间建立安全连接的核心环节,直接关系到数据传输的保密性和设备身份的真实性。​

byte轻骑兵的技术小窝 3573

基于C#通过PLCSIM ADV仿真软件实现与西门子1500PLC的S7通信方法演示

基于C#通过PLCSIM ADV仿真软件实现与西门子1500PLC的S7通信方法演示

Robot_PLC_HMI_Automation 3161

saxreader XML解析原理详解

//创建SAXReader对象解析xml SAXReader saxReader = new SAXReader(); //创建InputStream输入流对象获取xml文件的资源路径 InputStream resourceAsStream = TieCardClient.class.getClassLoader().getResourceAsStream("message/tieCar...

liudaka的博客 1149

YOLOv8【第二章:卷积创新篇·第23节】一文搞懂,Transformer与卷积混合架构!

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》,该专栏持续复现网络上各种热门内容(全网YOLO改进最全最新的专栏,质量分97分+,全网顶流),改进内容支持(分类、检测、分割、追踪、关键点、OBB检测)。且专栏会随订阅人数上升而涨价(毕竟不断更新),当前性价比极高,有一定的参考&学习价值,部分内容会基于现有的国内外顶尖人工智能AIGC等AI大模型技术总结改进而来,嘎嘎硬核。    ✨ 特惠福利:目前活动一折秒杀价!一次订阅,永久免费,所有后续更新内容均免费阅读!

**My Coding Family** 1388

java jdom dom4j_Java基础系列17:使用DOM、SAX、JDOM、DOM4J解析XML文件详解

一 简介在Java中,可以使用多种方式来解析XML文件,其中最常见的可能就是DOM、SAX、JDOM、DOM4J这四种方式了。其中,DOM和SAX这两种解析XML文件的方式有jdk自带的API,因此不需要额外引入第三方的jar包。与之相反的是,JDOM和DOM4J这两种解析方式都是第三方开源项目,因此在使用这两种方式解析XML文件时需要额外引入相关jar包(1)DOMDOM是用与平台和语言无关的方...

weixin_34125336的博客 566

软考「系统规划与管理师(第2版)」通关全攻略(2026年下半年)

它考的是一个IT管理者能不能用体系化的语言,把"我们为什么要建这个系统→怎么规划→怎么管好服务→怎么合规"讲圆。所以备考的核心策略也很明确——教材建框架 → 真题磨考点 → 案例练结构 → 论文备好真实项目素材 → 机考练打字。按计划走,不贪全、不盲刷、不死背,稳稳把三科都推过45分那条线。祝你通关 🎯。

软件行业技术文化交流。 3046

SAP OData 开发从入门到提高教程的目录

笔者 18 年的 SAP 技术开发生涯,对 SAP OData 服务的开发,测试,发布,部署,测试,及基于各种不同 SAP 技术实现的 OData 服务的幕后技术实现细节和使用场合,均有着深入的研究。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 7245

Claude Opus 4.7深度解析:高可靠智能体底座的工程化跃迁

大语言模型正从‘问答式助手’迈向‘可交付协作者’,其核心演进方向是推理严谨性与多模态工程能力。严谨性不再依赖提示词技巧,而是由动态计算图、前置验证链和自适应思考深度等底层架构支撑;视觉理解也突破传统patch建模,实现像素级组件识别与布局逻辑解析。这类能力显著提升长周期、多步骤、需自我校验的复杂任务闭环成功率,尤其适用于金融分析、代码自动化、UI转工程等强结果导向场景。Claude Opus 4.7正是这一范式转变的典型代表,它以高token消耗为代价,换取任务成功率从61%跃升至89%,并重塑人机协作节奏

weixin_33696822的博客 558

#systemverilog# 之 event region 和 timeslot 仿真调度(三)Verdi 辅助查看

通过今天的学习,我们知道:event region 是event sequence 的全集。我们打开了 event region feature 也就开启了event sequence 的功能。

那么菜的博客 1365

详解Java解析XML的四种方法—DOM/SAX/jdom/dom4j

最近在研究XML文件的生成和解析,网上资料很多,当然也参差不齐。写的没错误的通常是单独介绍了1种方法,介绍全的常常运行不起来。         小哆把4种方法汇总了一下,运行验证成功。     jar包免费下载: http://download.youkuaiyun.com/detail/sdsky1987/4083634     XML在不同的语言里解析方式都是一样的,只不过实现的

jyforzs的博客 1038

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

JAVA解析XML的方式DOM、SAX、DOM4J、JDOM、StAX之详解与比较

JAVA解析XML的方式DOM、SAX、DOM4J、JDOM、StAX之详解与比较 1.各种方式的详解 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找 特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信

java爱分享 1301

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Java基础系列17:使用DOM、SAX、JDOM、DOM4J解析XML文件详解

一 简介在Java中,可以使用多种方式来解析XML文件,其中最常见的可能就是DOM、SAX、JDOM、DOM4J这四种方式了。其中,DOM和SAX这两种解析XML文件的方式有jdk自带的API,因此不需要额外引入第三方的jar包。与之相反的是,JDOM和DOM4J这两种解析方式都是第三方开源项目,因此在使用这两种方式解析XML文件时需要额外引入相关jar包(1)DOMDOM是...

weixin_33755554的博客 691

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Java-详解Java解析XML的四种方法—DOM/SAX/jdom/dom4j

最近在研究XML文件的生成和解析,网上资料很多,当然也参差不齐。写的没错误的通常是单独介绍了1种方法,介绍全的常常运行不起来。         小哆把4种方法汇总了一下,运行验证成功。     jar包免费下载: http://download.youkuaiyun.com/detail/sdsky1987/4083634     XML在不同的语言里解析方式都是一样的,只不过实现的

箫枫-Phelovhl 1196
上一篇: JavaWeb之Servlet开发、HttpServlet开发
下一篇: JavaScripts实例:简易计算器
梦中的梦
博客等级 码龄18年 16粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值