Xml的(DTD,xml解析,xml建模)

目录

了解什么是良好的xml格式

xml(Extensible Markup Language)可拓展标记语言

既然提到json,那么也来说一下。

总结

1.DTD元素定义

属性定义的语法

xml特殊符号

2.xml文件解析

​编辑 生成xml文件代码演示

2.解析xml文件 

3.xml建模


了解什么是良好的xml格式

xml(Extensible Markup Language)可拓展标记语言

1)XML的简单易于在任何应用程序中读/写数据,这使XML很快成为数据交换的唯一公共语言,虽然不同的应用软件也支持其他的数据交换格式,但不久之后它们都将支持XML,那就意味着程序可以更容易的与Windows、Mac OS、Linux以及其他平台下产生的信息结合,然后可以很容易加载XML数据到程序中并分析它,并以XML格式输出结果。

2)xml可用作数据的说明、储存、传输

举个例子:假设一个微信群里面小明发了一条消息“你吃过没”。而这条消息发出后会被储存到服务器里,而当你进入微信的时候,这条消息就会从服务器里抓取过来显示到你的手机上。而这个抓取的过程中假设是以xml文件来传输(也有json,json和xml用途很相似,json、xml都有自己的格式,但其实都只是包装数据时格式不同而已,重要的是其中含有的数据,而不是包装的格式。这里只是举个例子)这时,我们用通俗易懂的文字来表示就是:

发送者:小明

聊天组:xxxx

信息:你吃过没

很明显我们人可以体会字面意思,并自动拆分出数据的,但机器却看不行,所以在传入之前它是通过xml的格式来让机器能识别的出来:

<msg>
      <sender ="小明" />
      <groupid = 112221 />
      <type = test/>
      <content = "你吃过没" />
</msg>

格式大概是这样,具体的如果感兴趣可以自己去网上看看,这里只是举个例子。这样表示就很直观,附带了对数据的说明,并且具备通用的格式规范可以让程序做解析。

3)xml文件现在多用于作配置文件,设置文件比较多,很多软件,框架都会采取xml作为配置文件。像在Android Studio中创建一个项目时,开始会弹出一个Configure your project(配置你的项目),而你在上面输入的项目名,包名什么的都会帮你存储到AndroidManifest.xml 文件里,此xml文件里还会默认配置好项目的一些属性和一个MainActivty以及这个activty的一些属性,并且在之后一些组件(Activty,service等)都是要在这里面注册并配置的。

既然提到json,那么也来说一下。

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。

1)JSON基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

2)json和xml优缺点对比:

①可读性方面。

JSON和XML的数据可读性基本相同,JSON和XML的可读性可谓不相上下,一边是建议的语法,一边是规范的标签形式,XML可读性较好些。

②可扩展性方面。

XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,JSON不能的。

③编码难度方面。

XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有http://json.org提供的工具,但是JSON的编码明显比XML容易许多,即使不借助工具也能写出JSON的代码,可是要写好XML就不太容易了。

④解码难度方面。

XML的解析得考虑子节点父节点,让人头昏眼花,而JSON的解析难度几乎为0。这一点XML输的真是没话说。

⑤流行度方面。

XML已经被业界广泛的使用,而JSON才刚刚开始,但是在Ajax这个特定的领域,未来的发展一定是XML让位于JSON。到时Ajax应该变成Ajaj(Asynchronous Javascript and JSON)了。

⑥解析手段方面。

JSON和XML同样拥有丰富的解析手段。

⑦数据体积方面。

JSON相对于XML来讲,数据的体积小,传递的速度更快些。

⑧数据交互方面。

JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互。

⑨数据描述方面。

JSON对数据的描述性比XML较差。

⑩传输速度方面。

JSON的速度要远远快于XML。

总结

xml与json的使用都比较类似,但如今程序员更青睐json, 而且市面上有各种各样现成的json开发库可直接使用。所以现在大多使用json来做为数据传输,如很多webservice的api 返回的大多是json格式。而xml现在一般主要用作配置文件,设置文件比较多。


1.DTD元素定义

拥有正确语法的 XML 被称为"形式良好"的 XML。

通过 DTD 验证的XML是"合法"的 XML。

符号 用途        示例说明
()  用来给元素分组 分成两组
|  在列出的对象中选择一个 表示男人或者女人必须出现,两者至少选其一
+ 该对象必须出现一次或者多次 表示成员必须出现,而却可以出现多个成员
* 该对象允许出现0次或者多次 爱好可以出现两次到多次
 该对象必须出现0次或者1次  菜鸟可以出现,也可以不出现,如果出现的话,最多只能出现一次
对象必须按指定的顺序出现   表示西瓜、苹果、香蕉必须出现,并且按这个顺序出现

属性定义的语法

<!ATTLIST element-name att_name type> (attlist可以存在多个属性,元素)(element-name放的是元素)(att_name放的是属性名称)(type属性类型)
ID (唯一的)
(男|女) “男” (枚举或默认)
CDATA (普通文本)
IDREF (类似数据库外键)

#REQUIRED/#IMPLIED(非空/可以空)


xml特殊符号


&(逻辑与) &amp ;
<(小于号) &lt;
.>(大于号) &gt ;
"(双引号) &quot ;
'(单引号) &qpos ;

SYSTEM (指的是引用当前项目的DTD)
PUBLIC (公开的,引用互联网上的DTD)
案例1

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persons[
	<!ELEMENT persons (person+)>
	<!ELEMENT person (name,age,contact,br*)>
	<!ELEMENT name (#PCDATA)>
	<!ELEMENT age (#PCDATA)>
	<!ELEMENT contact (phone|email)>
	<!ELEMENT br EMPTY>
	<!ATTLIST person
	  pid ID #REQUIRED
	  sex (男|女) '男'
	  qq CDATA #IMPLIED
	  parent IDREF #IMPLIED
	>
]>
<persons>
	<person pid="p1" sex="男" qq="aaa" parent="p2">
		<name>张小明</name>
		<age>10</age>
		<contact>
			<phone>1234567</phone>
		</contact>
		<br/>
	</person>
	<person pid="p2">
		<name>张大明</name>
		<age>35</age>
		<contact>
			<email>123@qq.com</email>
		</contact>
	</person>
</persons>

案例2

<?xml version="1.0" encoding="UTF-8"?>
	<!--
		config标签:可以包含0~N个action标签
	-->
<-- 
声明 config是根节点 然后他里面最少要有一个action 或多个
-->
<!DOCTYPE config[
		<!ELEMENT config (action+)>
		<!ELEMENT action (forward*)>
        <!ELEMENT forward EMPTY>
		<!ATTLIST action
		path  CDATA #REQUIRED
        type CDATA #REQUIRED
		>

		<!ATTLIST forward
				path CDATA #REQUIRED
				name CDATA #IMPLIED
				redirect (true|false) "false"
				>
		]>

<config>
	<!--
		action标签:可以饱含0~N个forward标签 path:以/开头的字符串,并且值必须唯一 非空 ,子控制器对应的路径
		type:字符串,非空,子控制器的完整类名
	-->
	<action path="/registerAction" type="test.action.RegisterAction">
		<forward name="success" path="/index.jsp" redirect="true" />
		<forward name="failed" path="/register.jsp" redirect="false" />
	</action>
	<action path="/loginAction" type="test.action.LoginAction">
		<forward name="a" path="/index.jsp" redirect="false" />
		<forward name="b" path="/welcome.jsp" redirect="true" />
	</action>
</config>

2.xml文件解析

所用jar包 dom4j 与 jaxen 

架包下载

xml解析架包  密码:hlx8

导入如上dom4j架包 与 jaxen

1,生成xml文件

所生成的xml文件 


 生成xml文件代码演示

package com.zking.listtext;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.junit.Test;

import java.io.File;
import java.io.FileOutputStream;

public class TextXml {
    /**
     * 使用DOM4J生成xml方法
     */
    @Test
    public static void createXml(){
        try {
            // 创建document对象
            Document document = DocumentHelper.createDocument();
            // 创建根节点bookRoot
            Element StudentRoot = document.addElement("StudentRoot");
            // 向根节点中添加第一个节点
            Element book1 = StudentRoot.addElement("student");
            // 向子节点中添加属性
            book1.addAttribute("id","1");
            // 向节点中添加子节点
            Element name = book1.addElement("name");
            // 向子节点赋值
            name.setText("小乔");
            Element price = book1.addElement("age");
            price.setText("18");
            // 向根节点中添加第二个节点
            Element book2 = StudentRoot.addElement("student");
            book2.addAttribute("id","2").addElement("name").setText("大桥");
            book2.addElement("age").setText("20");

            // 向根节点中添加第三个节点
            Element book3 = StudentRoot.addElement("student");
            book3.addAttribute("id","3").addElement("name").setText("孙策");
            book3.addElement("age").setText("21");

            // 设置生成xml的格式
            OutputFormat of = OutputFormat.createPrettyPrint();
            // 设置编码格式
            of.setEncoding("UTF-8");

            // 生成xml文件
            File file = new File("resources/Student.xml");
            if (file.exists()){
                file.delete();
            }
            //创建一个xml文档编辑器
            XMLWriter writer = new XMLWriter(new FileOutputStream(file), of);
            //把刚刚创建的document放到文档编辑器中
            writer.write(document);
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        TextXml.createXml();
    }
}

2.解析xml文件 

1.直接读取文件

 public static void analysis(){
        // 把要解析的xml变成file文件
        File file = new File("resources/Student.xml");

        // 获取解析器对象
        SAXReader reader = new SAXReader();
        // 把文件解析成document树
        Document document = null;
        try {
            document = reader.read(file);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        // 获取根节点
        Element studentRoot = document.getRootElement();
        // 获取根节点中所有节点
        List<Element> elements = studentRoot.elements();

      


        // 便利所有节点
        for (Element child : elements) {
            System.out.println("----------------");


            //已知属性名情况下
            System.out.println(Integer.parseInt(child.attributeValue("id")));//获取属性的数据
            //已知子元素名的情况下
            System.out.println(child.elementText("name"));//获取元素中值
            System.out.println(Integer.parseInt(child.elementText("age")));//获取元素中值



            //未知属性名情况下 使用 
            List<Attribute> attributes = child.attributes();
            for (Attribute attribute : attributes) {
                System.out.println(attribute.getName() + "---> " + attribute.getValue());
            }

            //未知子元素名情况下  子节点
            List<Element> elementList = child.elements();
            for (Element ele : elementList) {
                System.out.println(ele.getName() + "--->" + ele.getText());
            }
        }
        //把解析xml出来的数据集合打印
       // list.forEach(x-> System.out.println(x));
    }

2.通过类的加载器 文件在项目中时

 public static void xmlClass(){
        // 获取类的Class对象 在获取文件流对象
        Class<TextXml> ac = TextXml.class;
//                                加载器中的/代表本工作目录下找  src中
        InputStream in = ac.getResourceAsStream("/Student.xml");

        // 获取解析器对象
        SAXReader reader = new SAXReader();
        // 把文件解析成document树
        Document document = null;
        try {
            document = reader.read(in);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        // 获取根节点
        Element studentRoot = document.getRootElement();
        // 获取根节点中所有节点
        List<Element> elements = studentRoot.elements();



        // 便利所有节点
        for (Element child : elements) {
            System.out.println("----------------");


            //已知属性名情况下
            System.out.println(Integer.parseInt(child.attributeValue("id")));//获取属性的数据
            //已知子元素名的情况下
            System.out.println(child.elementText("name"));//获取元素中值
            System.out.println(Integer.parseInt(child.elementText("age")));//获取元素中值



            //未知属性名情况下 使用
            List<Attribute> attributes = child.attributes();
            for (Attribute attribute : attributes) {
                System.out.println(attribute.getName() + "---> " + attribute.getValue());
            }

            //未知子元素名情况下  子节点
            List<Element> elementList = child.elements();
            for (Element ele : elementList) {
                System.out.println(ele.getName() + "--->" + ele.getText());
            }
        }
        //把解析xml出来的数据集合打印
        // list.forEach(x-> System.out.println(x));
    }

3.xml建模

什么是建模,为什么要建模

1.什么是建模

建模就是针对xml配置文件键类的过程就是建模。

2.为什么要建模

为了方便在内存当中使用xml配置文件所以需要建模。

建模所用到的xml文件

<?xml version="1.0" encoding="UTF-8"?>
	<!--
		config标签:可以包含0~N个action标签
	-->
<!DOCTYPE config[
		<!ELEMENT config (action+)>
		<!ELEMENT action (forward*)>
        <!ELEMENT forward EMPTY>
		<!ATTLIST action
		path  CDATA #REQUIRED
        type CDATA #REQUIRED
		>

		<!ATTLIST forward
				path CDATA #REQUIRED
				name CDATA #IMPLIED
				redirect (true|false) "false"
				>
		]>

<config>
	<!--
		action标签:可以饱含0~N个forward标签 path:以/开头的字符串,并且值必须唯一 非空 ,子控制器对应的路径
		type:字符串,非空,子控制器的完整类名
	-->
	<action path="/registerAction" type="test.action.RegisterAction">
		<forward name="success" path="/index.jsp" redirect="true" />
		<forward name="failed" path="/register.jsp" redirect="false" />
	</action>
	<action path="/loginAction" type="test.action.LoginAction">
		<forward name="a" path="/index.jsp" redirect="false" />
		<forward name="b" path="/welcome.jsp" redirect="true" />
	</action>
</config>

开始建模  建模从里到外建模

那么先从最底层的<forward>元素开始,我们先仔细观察会发现<forward>元素中有三个属性分别是name,path,pedirect三个这里值得一提的是name属性是不能重复的,path属性是必须以“/”好开头了解完这些以后我们便可以开始着手写代码的首先把对应的属性在java类中创建好,然后写好get和set方法如下图所示

 因为path属性有限制必须以“/”号开头所以这里使用了正则表达式,在set方法中给path赋值之前进行判断如下图,这样我们的第一个元素类就写完了

set方法中用正则表达式进行判断


forward元素实体建模

package com.zking.resourt;



import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ForwardModel {
    private String name;
    private String path;
    private  boolean redirect=false;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        //通过反射 因为定义的正则时私有的  调用action模型中写好的正则
        Class<ActionModel> actionModelClass = ActionModel.class;
        try {

            Field pattern = actionModelClass.getDeclaredField("pattern");
            pattern.setAccessible(true);
            Pattern patten = (Pattern)pattern.get(actionModelClass);
            Matcher matcher = patten.matcher(path);
            boolean matches = matcher.matches();
            if(!matches){
                throw new RuntimeException("forward的path必须以”/“开头 并且不能重复");
            }
            this.path = path;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public boolean isRedirect() {
        return redirect;
    }

    public void setRedirect(String redirect) {
     //   System.out.println("方法中打印="+redirect.equals("true"));
        if(redirect.equals("true")){
        this.redirect = true;

        }else{
            this.redirect = false;
        }
        //或者
       // this.redirect=Boolean.parseBoolean(redirect);

    }

    @Override
    public String toString() {
        return "ForwardModel{" +
                "name='" + name + '\'' +
                ", path='" + path + '\'' +
                ", redirect=" + redirect +
                '}';
    }
    public ForwardModel(){
        super();
    }

    public static void main(String[] args) {
     new ForwardModel().setPath("/1");
    }
}

action元素实体建模

package com.zking.resourt;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ActionModel implements Serializable {

    private String path;
    private String type;

    private Map<String,ForwardModel> forw;
    //path必须一斜杠开头不能重复
    private static Pattern pattern=Pattern.compile("^/.+$");

    public  ForwardModel getForw(String key) {
        if(!forw.containsKey(key)){
            throw new RuntimeException("没有找到forward 所给的name:"+key
                    +"值");
        }

        return forw.get(key);
    }

    public void setForw(ForwardModel fw) {
        System.out.println(fw.getName());
        if(forw==null){
            forw=new HashMap<>();
        }
        if(forw.containsKey(fw.getName())){
            throw new RuntimeException("定义的forward 的name属性重复出现");
        }

        this.forw.put(fw.getName(), fw);
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        //用定义号的正则
        Matcher matcher = pattern.matcher(path);
        boolean matches = matcher.matches();
        if(!matches){
            throw new RuntimeException("action的path必须以”/“开头 并且不能重复");
        }
        this.path = path;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public ActionModel() {
    }

    @Override
    public String toString() {
        return "ActionModel{" +
                "path='" + path + '\'' +
                ", type='" + type + '\'' +
                ", forw=" + forw +
                '}';
    }
}

根节点config建模

package com.zking.resourt;

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

/**
 * 根节点模型
 */
public class ConfigModel {

  private Map<String,ActionModel> word;

  public  ActionModel getWord(String path) {
    if(!word.containsKey(path)){
      throw new RuntimeException("没有找到action 所给的path:"+path

              +"值");
    }

    return word.get(path);
  }

  public void setWord(ActionModel word) {

    if(this.word==null){
      this.word=new HashMap<>();
    }
     if(this.word.containsKey(word.getPath())){
       throw new RuntimeException("action 中的配置 属性 path重复加入 !!");
     }
         this.word.put(word.getPath(), word);
  }
}

解析并生成模型,测试

package com.baidu.resourt;

import java.io.InputStream;
import java.util.List;

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

/**
 * 文件解析保存 单例模式
 */
public final class ConfigModelFactory {

	private static String xmlFile = "/config.xml";

	private ConfigModelFactory() {

	}

	/*
	 * 定义根元素模型类
	 */
	private static ConfigModel cml = new ConfigModel();
	static {
		InputStream in = PropectiesRead.class.getResourceAsStream(xmlFile);

		SAXReader reaber = new SAXReader();

		// 把配置文件读取到内存
		Document read = null;
		try {
			read = reaber.read(in);
		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}

		// 获取根元素
		Element root = read.getRootElement();
		// 获取节点中confing下的action
		// Node node=read.selectSingleNode("/config");
		List<Element> list = root.selectNodes("/config/action");
		ActionModel ac = null;
		ForwardModel fo = null;
		for (Element action : list) {
			String path = action.attributeValue("path");
			String type = action.attributeValue("type");
			// 实例化子节点模型action
			ac = new ActionModel();
			// 属性加入模型中
			ac.setPath(path);
			ac.setType(type);
			
			// 获取action下所有的forward
			List<Element> forward = action.selectNodes("forward");
			for (Element ward : forward) {
				String fpath = ward.attributeValue("path");
				String name = ward.attributeValue("name");
				String s = ward.attributeValue("redirect");
				// 实例化子节点forward
				fo = new ForwardModel();
				/**
				 * 将获取的属性加入模型中
				 */
				fo.setPath(fpath);
				fo.setName(name);
				fo.setRedirect(s);
				ac.setForw(fo);
			}
			cml.setWord(ac);

		}

	}

	public static ConfigModel getConfing() {

		return cml;
	}

/*	public static void main(String[] args) throws Exception {
		
//		ActionModel word = ConfigModelFactory.getConfing().getWord("/bookAction");
//		System.out.println(word);

		// action中的属性 registerAction 需要获取的属性
		ActionModel word = null;

		word = ConfigModelFactory.getConfing().getWord("/bookAction");

		// System.out.println(word);
		// 获取forward中 属性下的failed
		System.out.println("-----"+word.getForw("booklist"));
	}
*/
}

解析指定文件 生成模型

package com.baidu.resourt;

import java.io.InputStream;
import java.util.List;

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

public class ConfigModelFactorys {
	 /**
		 * @param location xml文件的位置
		 * @return ConfigModel模型
		 * @throws Exception
		 */
		public static ConfigModel bulid(String location) throws Exception {
			InputStream stream = ConfigModelFactory.class.getResourceAsStream(location);
			if(stream==null) {
				throw new RuntimeException("xml文件位置有误:"+location);
			}
			SAXReader saxReader = new SAXReader();
			Document document = saxReader.read(stream);
			Node node = document.selectSingleNode("/config");
			if(node==null) {
				throw new RuntimeException("xml根节点必须为config");
			}
			ConfigModel cModel=new ConfigModel();
			List<Element> as = node.selectNodes("action");
			for (Element a : as) {
				//当前存在一个action标签  为它构建对应的模型ActionModel\
				ActionModel aModel=new ActionModel();
				//将xml属性变为模型的属性
				aModel.setPath(a.attributeValue("path"));
				aModel.setType(a.attributeValue("type"));
				//再当前的action底下去查询forward节点
				List<Element> fs = a.selectNodes("forward");
				for (Element f : fs) {//遍历forward标签  生成对应的模型ForwardModel
					ForwardModel fModel=new ForwardModel();
					//将xml属性变为模型的属性
					fModel.setName(f.attributeValue("name"));
					fModel.setPath(f.attributeValue("path"));
					fModel.setRedirect(f.attributeValue("redirect"));
					//将fModel放到aModel里面去
					aModel.setForw(fModel);
				}
				//将aModel放到cModel里面去
				cModel.setWord(aModel);
			}
			return cModel;
		}

}

最后测试结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值