XML基础 (1)

学习XML对任何类型的应用开发都很有帮助 比如可以在应用中有些经常要改变的配置或者像网站的后台管理DIY部分都可能会用到一些配置的修改  XML这种数据表现形式 是非常好的解决办法 另外对于学习AJAX也有很大的好处 因为DOM是一个已经标准化了的解析办法 在javascript中也会同样要处理文档结构 只是语法不同 只用再掌握JavaScript的DOM API 就可以很轻松的达到同样的效果

产生:   为了解决更清晰的表达层次结构和重复元素 使读写变得更简单 代替properties的一种方案

tips :

            1 XML是大小写敏感的

            2 XML的结束标签不能省略

            3 XML中 只有一个标签而没有相对应的结束标签的元素必须以 "/"结尾

            4 属性值必须用引号括起来

            5 所有属性值必须有属性

            6 最好值包括文本或者只包括子元素 不要两者兼有 避免出现:

 

< t1 >
        text1
        
< t2 > text2 </ t2 >
</ t1 >

 

           7 一个重要的规则: 属性只是用来修饰值

解析XML (以SUN的api为基础)

要构造一个DocumentBuilder对象 可以从DocumentBuilderFactory中得到

方法

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder
= factory.newDocumentBuilder();

然后就能获得一个Document对象

Document是XML的树型结构的具体形式的表现 由实现Node接口及多个子接口的对象构成

 

得到一个Document

File f = new  File( " bin/hibernate.cfg.xml " );
            
Document doc
= builder.parse(f);

一些其他的构造方法(DocumentBuilder)

abstract  DocumentnewDocument()
          获取 DOM Document 对象的一个新实例来生成一个 DOM 树。
 Documentparse(File f)
          将给定文件的内容解析为一个 XML 文档,并且返回一个新的 DOM Document 对象。
abstract  Documentparse(InputSource is)
          将给定输入源的内容解析为一个 XML 文档,并且返回一个新的 DOM Document 对象。
 Documentparse(InputStream is)
          将给定 InputStream 的内容解析为一个 XML 文档,并且返回一个新的 DOM Document 对象。
 Documentparse(InputStream is, String systemId)
          将给定 InputStream 的内容解析为一个 XML 文档,并且返回一个新的 DOM Document 对象。
 Documentparse(String uri)
          将给定 URI 的内容解析为一个 XML 文档,并且返回一个新的 DOM Document 对象。

 

API中看出可以用URL和IO中的类来构造Document

重要接口

Node 是整个对象模型的主要数据类型 表示该文档树的单个节点 实现Node的接口有 Document   Text    Element   Entity

        tip : 并不是所有的Node都有子节点 如text 不同的接口会有更加合理和简单的获取和设置的相关方法

Document是用来表示整个XML或者Html之类的文档 是文档的根 提供数据的访问和构造以及修改方法

        另:document也是实现Node的接口

NodeList接口提供对节点的有序集合的抽象,没有定义或约束如何实现此集合。DOM 中的 NodeList 对象是活动的。

    NodeList 中的项可以通过从 0 开始的整数索引进行访问。

Text 表示Element或者Attr的文本内容

Element 接口表示 HTML 或 XML 文档中的一个元素。元素可能有与它们相关的属性;由于 Element 接口继承自 Node,所以可以使用一般 Node 接口属性 attributes 来获得元素所有属性的集合。Element 接口上有通过名称获得 Attr 对象或通过名称获得属性值的方法。在 XML 中(其中的属性值可能包含实体引用),应该获得 Attr 对象来检查表示属性值的可能相当复杂的子树。另一方面,在 HTML 中(其中的所有属性都有简单的字符串值),可以使用直接访问属性值的方法,这既安全又便捷。

NamedNodeMap   实现 NamedNodeMap 接口的对象用于表示可以通过名称访问的节点的集合。注意,NamedNodeMap 不从 NodeList 继承;不以任何特定的顺序维护 NamedNodeMaps。在实现 NamedNodeMap 的对象中包含的对象还可以通过顺序索引进行访问,但只允许方便地枚举 NamedNodeMap 的内容,并不意味着 DOM 指定这些节点的顺序。

例子:

解析一个xml文档来 基本接口及其方法的应用

我就把我的hibernate.cfg.xml拿来玩 当然Hibernate本身是用Dom4J的

<? xml version='1.0' encoding='UTF-8' ?>
<! DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"
>

<!--  Generated by MyEclipse Hibernate Tools.                    -->
< hibernate-configuration >
    
< session-factory >
            
< property  name ="connection.driver_class" > com.mysql.jdbc.Driver </ property >
            
< property  name ="connection.url" > jdbc:mysql://localhost:3306/sshtest </ property >
            
< property  name ="connection.username" > root </ property >
            
< property  name ="connection.password" > 00000000 </ property >
            
            
<!--  JDBC connection pool  -->  
            
< property  name ="hibernate.connection.provider_class" > org.hibernate.connection.C3P0ConnectionProvider </ property >
        
< property  name ="hibernate.c3p0.max_size" > 20 </ property >     
        
< property  name ="hibernate.c3p0.min_size" > 5 </ property >     
        
< property  name ="hibernate.c3p0.timeout" > 120 </ property >     
        
< property  name ="hibernate.c3p0.max_statements" > 100 </ property >     
        
< property  name ="hibernate.c3p0.idle_test_period" > 120 </ property >     
        
< property  name ="hibernate.c3p0.acquire_increment" > 2 </ property >
        
        
< property  name ="hibernate.transaction.factory_class" > org.hibernate.transaction.JDBCTransactionFactory </ property >
            
            
<!--  SQL dialect  -->
            
< property  name ="dialect" > org.hibernate.dialect.MySQLDialect </ property >
            
< property  name ="current_session_context_class" > thread </ property >      
            
< property  name ="cache.provider_class" > org.hibernate.cache.NoCacheProvider </ property >     
            
< property  name ="show_sql" > true </ property >
            
<!-- <property name="hbm2ddl.auto">create</property> -->
         
        
< mapping  resource ="com/ergal/hibernate/pojo/User.hbm.xml" />
        
< mapping  resource ="com/ergal/hibernate/pojo/Artist.hbm.xml" />
        
< mapping  resource ="com/ergal/hibernate/pojo/Category.hbm.xml" />
        
< mapping  resource ="com/ergal/hibernate/pojo/FileType.hbm.xml" />
        
< mapping  resource ="com/ergal/hibernate/pojo/MyFile.hbm.xml" />
        
< mapping  resource ="com/ergal/hibernate/pojo/MyLocation.hbm.xml" />
        
< mapping  resource ="com/ergal/hibernate/pojo/MyPackage.hbm.xml" />
        
< mapping  resource ="com/ergal/hibernate/pojo/MyPic.hbm.xml" />

    
</ session-factory >
</ hibernate-configuration >

下面写一个类Test.java

package  com.ergal;

import  java.io.File;
import  java.io.IOException;
import  javax.xml.parsers.DocumentBuilder;
import  javax.xml.parsers.DocumentBuilderFactory;
import  javax.xml.parsers.ParserConfigurationException;
import  org.w3c.dom.Document;
import  org.w3c.dom.Element;
import  org.w3c.dom.Node;
import  org.w3c.dom.NodeList;
import  org.w3c.dom.Text;
import  org.xml.sax.SAXException;


public   class  Test 
{
    
public static void main(String[] args) throws IOException
    
{
        
try
        
{
            DocumentBuilderFactory factory
=DocumentBuilderFactory.newInstance();
            DocumentBuilder builder
=factory.newDocumentBuilder();
            
            File f
=new File("bin/hibernate.cfg.xml");
            
            
//得到文档
            Document doc=builder.parse(f);
            
            
//得到根元素
            Element root=doc.getDocumentElement();
            
            
        }
catch(ParserConfigurationException e)
        
{
            e.printStackTrace();        
        }
catch (SAXException e) {
            e.printStackTrace();
        }

    }
    
}

这里面的root就是获得的根元素 来看看它的名字是什么 Node里有getNodeName的方法

Element里有 getTagName的方法 在这里都可以用 在后面添加以下代码:

// 获得根元素的名字
String rootElementName = root.getNodeName();
// String rootElementName=root.getTagName();
System.out.println(rootElementName);

Console 里就会打印

 hibernate-configuration

 

 现在 要获得hibernate-configuration下的所有子节点 (事实上只有一个) 就要用到 NodeList这个接口和

Element的getChildNodes()这个方法

添加以下代码

             // 得到子节点的集合
            NodeList childrenNodes = root.getChildNodes();
            
            
// 得到字节点的个数
             int  nodeSize = childrenNodes.getLength();
            
            System.out.println(nodeSize);
            
// 在for中得到各个子节点
             for ( int  i = 0 ; i < nodeSize; i ++ )
            
{
                Node child
=childrenNodes.item(i);
                System.out.println(child.getNodeName()
+" "+child.getNodeValue());
            }

在Console 打印的结果是

3
#text

    
session-factory
null
#text


很明显了 这就可以解释那些Node的子接口分别的作用了  Elemnet 表示元素 这里只有session-factory

另外其他空白区域的就是 Text 它的nodeName 就是#text    Hibernate的session-factory 的nodeValue为null

所有的内容都可以找到相应的一种Node 如 Element Text 还有注释Comment 等等

这些在Node的API中有明确的定义 如下:

包括属性 nodeNamenodeValueattributes 作为一种获取节点信息的机制,无需向下强制转换为特定的派生接口。在没有对特定的 nodeType(如 ElementnodeValueCommentattributes)的属性的明显映射的情况下,这将返回 null。注意,特定的接口可能包含其他更方便的机制来获取和设置相关信息。

nodeNamenodeValueattributes 的值将根据以下节点类型的不同而不同。

InterfacenodeNamenodeValueattributes
AttrAttr.name 相同Attr.value 相同null
CDATASection"#cdata-section"CharacterData.data 相同,CDATA 节的内容null
Comment"#comment"CharacterData.data 相同,该注释的内容null
Document"#document"nullnull
DocumentFragment"#document-fragment"nullnull
DocumentTypeDocumentType.name 相同nullnull
ElementElement.tagName 相同nullNamedNodeMap
Entityentity namenullnull
EntityReference引用的实体名称nullnull
Notationnotation namenullnull
ProcessingInstructionProcessingInstruction.target 相同ProcessingInstruction.data 相同null
Text"#text"CharacterData.data 相同,该文本节点的内容null

 在所有的Node里面 现在看来 对我们有用的只有Element 在这里就是session-factory

因此可以加上一个条件

 

                Node child = childrenNodes.item(i);
                
if (child  instanceof  Element)
                
{
                    System.out.println(child.getNodeName());
                }


也可以把这个Node转换为Element来分析

这样Console得到的结果就是

session-factory

因为已经知道一共有3个节点 而且在session-factory这个节点前有#text 后面也是#text  中间才是有用的元素

所以这里可以用另外一种方法来得到session-factory这个节点

            Node firstNode = root.getFirstChild();
            Node secondNode
= firstNode.getNextSibling();

效果是一样的

现在可以来遍历sessionFactory里的元素

再看看hibernate.cfg.xml中 在session-factory 中 有好几种Node 有注释 有空白 有元素嵌套(或者说元素里面还有)元素

现在这么写来遍历sessionFactory里的元素

             // 得到session-factory的子节点的集合
            NodeList thirdNode = secondNode.getChildNodes();
            
// 得到子节点的数量
             int  tNodeLength = thirdNode.getLength();
            
// 循环得到子节点
             for ( int  j = 0 ; j < tNodeLength; j ++ )
            
{
                Node thChildNode
=thirdNode.item(j);
                
if(thChildNode instanceof Element)
                
{
                    System.out.println(thChildNode.getNodeName());
                }

            }

在Console里的结果就是

property
property
property
property
property
property
property
property
property
property
property
property
property
property
property
property
mapping
mapping
mapping
mapping
mapping
mapping
mapping
mapping

这是把空白和注释都过滤掉了的剩下的元素 其实完全可以再细化一下

因为mapping是只有属性的 而property是既有属性也有子节点的(差点写成了子元素) 

另:在不知道属性名的情况下是无法获得属性的 Node里的方法getAttributes()返回的是NameNodeMap

这个和NodeList的区别是 只有在有Name的情况下才能访问 就是此集合是通过名称访问节点的集合

而Element里的方法也都需要知道属性名 难道就只有一直 if else 下去来遍历

虽然hibernate是用的Dom4j 我还是看了一下Hibernate的源代码

在Configuration有如下一个方法

     private   void  addProperties(Element parent)  {
        Iterator iter 
= parent.elementIterator( "property" );
        
while ( iter.hasNext() ) {
            Element node 
= (Element) iter.next();
            String name 
= node.attributeValue( "name" );
            String value 
= node.getText().trim();
            log.debug( name 
+ "=" + value );
            properties.setProperty( name, value );
            
if ( !name.startsWith( "hibernate" ) ) {
                properties.setProperty( 
"hibernate." + name, value );
            }

        }

        Environment.verifyProperties( properties );
    }

这样把键值都取出来再交给parseSessionFactory()方法去解析

parseSessionFactory()的代码如下

     private   void  parseSessionFactory(Element sfNode, String name)  {
        Iterator elements 
= sfNode.elementIterator();
        
while ( elements.hasNext() ) {
            Element subelement 
= (Element) elements.next();
            String subelementName 
= subelement.getName();
            
if ( "mapping".equals( subelementName ) ) {
                parseMappingElement( subelement, name );
            }

            
else if ( "class-cache".equals( subelementName ) ) {
                String className 
= subelement.attributeValue( "class" );
                Attribute regionNode 
= subelement.attribute( "region" );
                
final String region = ( regionNode == null ) ? className : regionNode.getValue();
                
boolean includeLazy = !"non-lazy".equals( subelement.attributeValue( "include" ) );
                setCacheConcurrencyStrategy( className, subelement.attributeValue( 
"usage" ), region, includeLazy );
            }

            
else if ( "collection-cache".equals( subelementName ) ) {
                String role 
= subelement.attributeValue( "collection" );
                Attribute regionNode 
= subelement.attribute( "region" );
                
final String region = ( regionNode == null ) ? role : regionNode.getValue();
                setCollectionCacheConcurrencyStrategy( role, subelement.attributeValue( 
"usage" ), region );
            }

            
else if ( "listener".equals( subelementName ) ) {
                parseListener( subelement );
            }

            
else if ( "event".equals( subelementName ) ) {
                parseEvent( subelement );
            }

        }

    }

然后在把不同的元素 交给不同的处理器 比如 mapping就用parseMappingElement( subelement, name );

也是用if else的方法来取得值的 看来我的想的也八九不离十

好 回到我的例子中 我就不一一按属性的名来获得值了 就直接获得所有的元素的值 只有属性的mapping就可以很方便的获得属性值

于是修改如下 并且根据Text的getData 方法(确切的说是CharactorData的方法)等 来获取每个元素的属性值和子节点的text

             // 得到session-factory的子节点的集合
            NodeList thirdNode = secondNode.getChildNodes();
            
// 得到子节点的数量
             int  tNodeLength = thirdNode.getLength();
            
// 循环得到子节点
             for ( int  j = 0 ; j < tNodeLength; j ++ )
            
{
                Node thChildNode
=thirdNode.item(j);
                
//得到有子节点的元素
                if(thChildNode instanceof Element && thChildNode.hasChildNodes())
                
{
                    
//将节点转换为元素
                    Element thChildElement=(Element)thChildNode;
                    
//获得text
                    Text textNode=(Text)thChildElement.getFirstChild();
                    
//得到该元素的值 这里的trim方法可以去掉前后的空白
                    String text=textNode.getData().trim();
                    System.out.println(text);                                                    
                }

                
//得到没有子节点 只有属性的mapping元素
                else if(thChildNode instanceof Element && !thChildNode.hasChildNodes())
                
{
                    
//将节点转换为元素
                    Element thChildElement=(Element)thChildNode;
                    
//获得属性的值
                    String text=thChildElement.getAttribute("resource");
                    System.out.println(text);
                }

            }

 

这样Console的结果就是

com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/sshtest
root
00000000
org.hibernate.connection.C3P0ConnectionProvider
20
5
120
100
120
2
org.hibernate.transaction.JDBCTransactionFactory
org.hibernate.dialect.MySQLDialect
thread
org.hibernate.cache.NoCacheProvider
true
com/ergal/hibernate/pojo/User.hbm.xml
com/ergal/hibernate/pojo/Artist.hbm.xml
com/ergal/hibernate/pojo/Category.hbm.xml
com/ergal/hibernate/pojo/FileType.hbm.xml
com/ergal/hibernate/pojo/MyFile.hbm.xml
com/ergal/hibernate/pojo/MyLocation.hbm.xml
com/ergal/hibernate/pojo/MyPackage.hbm.xml
com/ergal/hibernate/pojo/MyPic.hbm.xml

这些是最基本的DOM解析方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值