XML的学习总结

  1. XML:可扩展标记语言,该标记语言作为接口使用的比较多
  2. 简介:
    xml:Extensible Markup Language
    HTML:Hyper text Markup Language 用于数据显示
    GML:General Markup Language 用于数据存储和传输
  3. xml文档结构
    1、xml文档是由标签[元素,节点]组成
    2、在xml文档的最开始的位置需要指定头信息[指令],头信息也可以不写,但是在某些
    xml文档解析器不能通过,浏览器是xml文档的一种解析器
头文件       <?xml version = "1.0" encoding = "UTF-8"?>

<?xml version = "1.0" encoding = "UTF-8"?>
<root>
	<child>
		<subline>
			lhm
		</subline>
	</child>
</root>
  1. 一个xml文档必须要有跟标签;在xml文档中,标签是成对出现的,由开始标签和结束标签构成;一个xml文档只能有一个跟标签
    1、xml标签对大小写敏感,前后标签大小写要一致
    2、xml标签必须要正确的嵌套;在xml标签中可以出现其他xml标签
    3、在没有xml验证的情况下,一个xml文档中可以出现任意的自定义标签
    4、xml的标签可以有属性,属性是由属性名和属性值构成,中间以等号连接,并且属性值必须使用双引号;并且可以有多个属性,每个属性之间用空格分隔,第一个属性名和标签名必须要有空格;在同一个标签中,属性不可以重复
    5、xml文档中的注释:xml文档中的注释不可以嵌套使用
    格式:
<!--注释内容-->
  1. PCDATA和CDATA
    1、PCDATA:可被解析的字符数据;xml文档中的所有内容都是PCDATA
    2、CDATA:在xml文档中不会被xml解析器所解析的字符数据,当xml中的某些数据不希望被xml解析器所解析时,就使用CDATA标签包裹此数据
<![CDATA[不想被解析的数据。。。。。。。。。。。]]>
  1. xml中的实体引用
    1、xml中的实体:在xml文档中,某些符号具有特殊含义,但是有些时候xml中的数据需要用到这些符号,但是如果直接使用,会被xml解析器所解析,可以考虑使用实体引用的方式使用特殊符号:
语法:&实体名
单引号:&apos;
双引号:&quot;
&符号:&amp;
>符号:&gt;
<符号:&lt;
  1. 自定义实体,写在标签外面
语法:
<!DOCTYPE 根元素名 [
 <!ENTITY 实体名 实体内容 >
<!ENTITY 实体名 实体内容 >
 ...
]>
  1. xml中的空格,xml文档中的空格不会被保留,写多个空格也只会有一个空格
  2. xml的命名空间
    1、命名空间主要解决当多个xml文件中存在相同名称的标签但却表达的意思不同时这多个xml文档一起使用时的命名冲突问题
    解决方式:
    2、命名空间前缀:给xml文档的所有标签都加上前缀,但是需要该标签中定义
    该命名空间前缀,语法:xmlns:前缀名=“URI”
    格式:前缀:标签名
<students1:students xmlns:students1="http://briup.com/students1">
    <students1:student>
        <students1:name>张三 </students1:name>
    </students1:student>
<students1:students>

默认命名空间:
<students xmlns="http://briup.com/students1">
    <student>
        <name>张三 </name>
    </student>
<students>
  1. 约束
    1、DTD约束
    DTD:Document Type Definition:文档类型定义
    内部DTD:将DTD约束写在xml文档内部
    外部DTD:将DTD约束以单独的文件存在,在xml文档中引用该DTD约束文件
    混合DTD:既有内部也有外部
    属性约束
    2、Schema约束
    <!DOCTYPE 根标签[
    <!ENTITY 实体名 "实体内容 ">
    <!ELEMENT 元素名 (内部模式 )>
    <!ATTLIST 元素名 属性名 属性类型 属性默认值 /属性特点
    属性名 属性类型 属性默认值 /属性特点
    .
    .
    .
    ]>
    
  2. 解析
    1、DOM解析(jdk自带)Document Object Model
    1.1、需要将整个xml文档加载至内存中,不适用与大文件
    1.2、优点:能够将整个xml文档解析成相关的对象,能够对其进行增删改查
    1.3、被文档视为一种树结构。这种树结构被称为节点树。文档中的每个成分都是一个节点( Node)。可通过这棵树访问所有节点。可以修改或删除它们的内容,也可以创建新的元素。
    1.3.1、整个文档是一个文档节点 (Document)
    1.3.2、每个 XML标签是一个元素节点 (Element)
    1.3.3、包含在 XML元素中的文本是文本节点 (TextNode)
    1.3.4、每一个 XML属性是一个属性节点 (AttributeNode)
    1.3.5、注释属于注释节点 (CommentNode)
    1.4、文本总是存储在文本节点中,在 DOM处理中一个普遍的错误是,认为元素节点包含 文本。不过,元素节点的文本是存储在文本节点中的。
    比如:<year>2005</year>,元素节点 <year>,拥有一个值为 "2005"的文本点。
    "2005"不是 <year>元素的值!
/*
使用DOM来解析XML文档,遍历输出到控制台
 */
public class DomToXml {
    public static void main(String[] args) throws Exception {
        //创建文档创建器
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        //创建DOM文档
        InputStream is = DomToXml.class.getResourceAsStream("/pom.xml");
        if (is == null){
            throw new RuntimeException("流文件为null。。。。。");
        }
        Document document = builder.parse(is);
        System.out.println(document);//[#document: null]

        //获取xml文件的根元素
        Element rootElement = document.getDocumentElement();
        System.out.println(rootElement);//[project: null]

        parse(rootElement);
    }

    public static void parse(Node node){
        //如果是Document节点对象,则获得根节点对象,再传递至该方法
        if (node.getNodeType() == Node.DOCUMENT_NODE){
            //将该节点对象转为文档节点对象
            Document doc = (Document) node;
            //获取该文档节点对象的根节点
            Element rootElement = doc.getDocumentElement();
            //将这个根节点对象传递到此方法中
            parse(rootElement);
        }

        //如果node是Element节点对象,打印节点名称,打印属性,获取其子节点
        if (node.getNodeType() == Node.ELEMENT_NODE){
            //将node对象强转为Element对象
            Element element = (Element) node;
            //获取该节点元素的名称
            String tagName = element.getTagName();

            //判断该节点是否含有属性
            boolean flag = element.hasAttributes();

            //输出节点名称,如果该节点有属性,那么节点名称后面加上空格
            System.out.print("<" + tagName + (flag?" ":""));

            //输出包含该节点的属性
            if (flag){
                //得到节点属性对象
                NamedNodeMap attrs = element.getAttributes();
                int length = attrs.getLength();
                for (int i = 0; i < length;i++){
                    Attr attr = (Attr)attrs.item(i);
                    String attrName = attr.getName();
                    String attrValue = attr.getValue();
                    System.out.print(attrName + "=\"" +attrValue + "\"" + (i == length-1?"":" "));
                }
            }
            System.out.print(">");

            //获得该根节点的所有子节点,,包括文本节点
            NodeList nl = element.getChildNodes();
            for(int i = 0; i < nl.getLength();i++){
                Node node1 = nl.item(i);
                //将该节点作为子根节点,作为此方法的参数
                parse(node1);
            }
            System.out.print("</" + tagName + ">");
        }

        //如果该内容是文本内容,不是属性内容,那么也要打印出来
        if (node.getNodeType() == Node.TEXT_NODE){
            //将该节点转为文本节点
            Text text = (Text) node;
            //返回 Text节点的逻辑相邻文本节点的所有文本到此节点,以文档顺序连接。
            String value = text.getWholeText();
            System.out.print(value);
        }
    }
}

使用DOM解析xml并对他进行CRUD(增删改查)

public class DomToXmlCRUD {
    public static void main(String[] args) throws Exception {
        Document document = CreateDoc(new File("D:\\code\\workspace_IdeaUi\\xml_parse\\src\\main\\resources\\Student.xml"));
        Updata(document,"005","李煌民");
    }

    /**
     *
     * @param file  IO中的文件流作为形式参数
     * @return Document对象
     * @throws Exception   抛出的异常以最大的异常为准
     */
    //获取Document对象
    public static Document CreateDoc(File file) throws Exception {
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document = builder.parse(file);
        return document;
    }

    //通过节点来遍历整个XML文档
    public static void ReadByNodeName(Node node){
        //如果该节点是一个标签节点
        if (node.getNodeType() == Node.ELEMENT_NODE){
            System.out.println("该标签节点名字为:" + node.getNodeName());
            System.out.println("该标签节点类型为:" + node.getNodeType());
            System.out.println("该标签节点值为:" + node.getNodeValue());
        }
        //获得该节点的所有子节点
        NodeList nl = node.getChildNodes();
        //遍历所有的子节点
        for (int i = 0; i < nl.getLength(); i++) {
            Node node1 = nl.item(i);
            //将所有的子节点变成根节点来遍历该子节点下面的子节点
            ReadByNodeName(node1);
        }
    }

    //因为增删改都需要使用Transform来将xml文件进行更新
    public static void ReadXmlFromRamToFile(File file,Document document) throws TransformerException {
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer tf = factory.newTransformer();
        //将内存的中xml读取到程序中
        DOMSource source = new DOMSource(document);
        //将读入的xml写入到指定的文件中
        StreamResult result = new StreamResult(file);
        tf.transform(source,result);
    }

    //查找方法,通过传入一个标签序号来查找对应的标签
    public static void Select(Document document,int itemNum){
        Element student = (Element)document.getElementsByTagName("student").item(itemNum - 1);
        if (student != null){
            //获得其id属性
            String id = student.getAttribute("id");
            //获得Sex属性值
            String sex = student.getAttribute("sex");
            // 分别获得第itemNum-1个元素下的name、age、intro的文本值
            // 因为第itemNum-1个student下只有一个name元素,所以使用item(0),age和intro亦然
            String name = student.getElementsByTagName("name").item(0).getTextContent();
            String age = student.getElementsByTagName("age").item(0).getTextContent();
            String intro = student.getElementsByTagName("intro").item(0).getTextContent();
            System.out.println(id + "---" + sex + "---" + name + "---" + age + "---" + intro);
        }else {
            System.out.println("该" +itemNum+ "学生不存在");
        }
    }

    //删除方法,根据传入的第几个元素进行删除
    public static void Delete(Document document,int studentNum) throws TransformerException {
        Element student = (Element)document.getElementsByTagName("student").item(studentNum - 1);
        if (student != null){
            student.getParentNode().removeChild(student);
            System.out.println("删除成功。。。。");
        }else {
            System.out.println("删除第" + studentNum + "位学生失败。。。。");
        }

        //将内存中的信息更新到新的xml文件中
        ReadXmlFromRamToFile(new File("D:\\code\\workspace_IdeaUi\\xml_parse\\newStudent.xml"),document);
    }

    //增加方法,传入标签名字,属性值
    public static void Create(
            Document document,
            String Student_name,
            String Student_id,
            String Student_sex,
            String Student_age,
            String Student_intro) throws TransformerException {
        //找到跟节点,根节点只有一个
        Element students = (Element)document.getElementsByTagName("students").item(0);
        //创建各个节点
        Element ele_student = document.createElement("student");
        ele_student.setAttribute("id",Student_id);
        ele_student.setAttribute("sex",Student_sex);
        Element ele_name = document.createElement("name");
        ele_name.setTextContent(Student_name);
        Element ele_age = document.createElement("age");
        ele_age.setTextContent(Student_age);
        Element ele_intro = document.createElement("intro");
        ele_intro.setTextContent(Student_intro);
        //使用appendChild方法增加父子关系
        students.appendChild(ele_student);
        ele_student.appendChild(ele_name);
        ele_student.appendChild(ele_age);
        ele_student.appendChild(ele_intro);
        //写入到xml文件中
        ReadXmlFromRamToFile(new File("D:\\code\\workspace_IdeaUi\\xml_parse\\newStudent.xml"),document);
        System.out.println("添加成功。。。。。");
    }

    //修改方法
    public static void Updata(Document document,String id,String newName) throws TransformerException {
        boolean isFund = false;
        //获得student节点集合
        NodeList nl = document.getElementsByTagName("student");
        //遍历student集合,并从中获得其id属性为传入的id值的元素,然后修改其元素下的name的文本值
        for (int i = 0; i < nl.getLength(); i++) {
            Element item = (Element)nl.item(i);
            if (id.equalsIgnoreCase(item.getAttribute("id"))){
                item.getElementsByTagName("name").item(0).setTextContent(newName);
                isFund = true;
                break;
            }
        }

        if (isFund){
            //写入到新的xml文件中
            ReadXmlFromRamToFile(new File("D:\\code\\workspace_IdeaUi\\xml_parse\\newStudent.xml"),document);
            System.out.println("修改成功。。。。");
        }else {
            System.out.println("修改失败.....");
        }
    }

}

//用到的xml文件
<?xml version="1.0" encoding="utf-8" ?>
<students>
    <student id="001" sex="男">
        <name>周星驰</name>
        <age>23</age>
        <intro>这是一位成绩很好的学生</intro>
    </student>
    <student id="002" sex="男">
        <name>刘德华</name>
        <age>32</age>
        <intro>他综合能力很优秀</intro>
    </student>
    <student id="003" sex="女">
        <name>周惠敏</name>
        <age>31</age>
        <intro>长得漂亮</intro>
    </student>
    <student id="004" sex="男">
        <name>王五</name>
        <age>37</age>
        <intro>成绩有点差</intro>
    </student>
    <student id="005" sex="男">
        <name>张三丰</name>
        <age>26</age>
        <intro>经常逃课</intro>
    </student>
</students>

2、SAX(Simple API for xml)解析(jdk自带)
1、优点不用将xml加载至内存,读取一行解析一行,该解析方式类似于事件处理模型,解析到相关的元素就触发相关的方法
2、缺点:由于不能将整个xml文档加载至内存,一般不能进行增删改查(过程复杂)

/*
使用SAX来解析XML文件
 */
public class SaxToXml {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        //1、获取SAXParserFactory对象
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setNamespaceAware(true);

        //2、获取SAXParser对象
        SAXParser parser = factory.newSAXParser();

        //3、解析
        parser.parse(
                SaxToXml.class.getResourceAsStream("/Student.xml"),
                new DefaultHandler(){
                    @Override
                    public void startDocument() throws SAXException {
                        System.out.println("开始解析文档。。。。");
                    }

                    @Override
                    public void endDocument() throws SAXException {
                        System.out.println("结束解析文档。。。。");
                    }

                    @Override
                    public void startElement(
                            String uri,//当前标签的命名空间的内容
                            String localName,//标签名
                            String qName,//带命名空间的标签名
                            Attributes attributes//当前标签的属性
                    ) throws SAXException {
                        int length = attributes.getLength();
                        System.out.print("<" + qName + (length == 0?"":" "));

                        for (int i = 0; i < length; i++) {
                            String attributesQName = attributes.getQName(i);
                            String attributesValue = attributes.getValue(i);
                            System.out.print(attributesQName + "=\"" + attributesValue + "\"");
                        }
                        System.out.print(">");
                    }

                    @Override
                    public void endElement(String uri, String localName, String qName) throws SAXException {
                        System.out.print("</" + qName + ">");
                    }
                    /*
                    //每次遇到字符就会调用此方法,空格也是字符,也会调用
                    //ch是传回来的字符数组,其包含从开始解析到当前这一段文本,包含着所有的元素内容
                    //start和 length分别是当前文本在数组中的开始位置和结束位置 。
                    */
                    @Override
                    public void characters(char[] ch, int start, int length) throws SAXException {
                        System.out.print(new String(ch,start,length));
                    }
                }
        );
    }
}

3、DOM4J解析(使用第三方jar包)

常用API 
class org.dom4j.io.SAXReader
    read  提供多种读取xml文件的方式,返回一个Domcument对象 
interface org.dom4j.Document
    iterator  使用此法获取node
    getRootElement  获取根节点 
interface org.dom4j.Node
    getName  获取node名字,例如获取根节点名称为bookstore
    getNodeType  获取node类型常量值,例如获取到bookstore类型为1——Element
    getNodeTypeName  获取node类型名称,例如获取到的bookstore类型名称为Element 
interface org.dom4j.Element
    attributes  返回该元素的属性列表
    attributeValue  根据传入的属性名获取属性值
    elementIterator  返回包含子元素的迭代器
    elements  返回包含子元素的列表   
interface org.dom4j.Attribute 
    getName  获取属性名
    getValue  获取属性值    
interface org.dom4j.Text
    getText  获取Text节点值
interface org.dom4j.CDATA 
    getText  获取CDATA Section值
interface org.dom4j.Comment
    getText  获取注释 

使用DOM4J进行增删改查

/*
使用Dom4J对xml文件进行增删改查
 */
public class UserDom4JToCRUD {
    public static void main(String[] args) throws DocumentException, IOException {
        //创建SAXReader对象
        SAXReader reader = new SAXReader();

        //读取整个XML文档加载到内存中
        Document document = reader.read(Dom4jToXml.class.getResourceAsStream("/Student.xml"));

        Create(document);
    }

    //将Document写入到新文件中-----普通输出
    public static void Writer(Document document) throws IOException {
        FileWriter fw = new FileWriter("D:\\code\\workspace_IdeaUi\\xml_parse\\Dom4jStudent.xml");
        document.write(fw);
        fw.close();
    }

    //简单输出紧凑的样式
    public static void Writer1(Document document) throws IOException {
        FileWriter fw = new FileWriter("D:\\code\\workspace_IdeaUi\\xml_parse\\Dom4jStudent.xml");
        OutputFormat of = OutputFormat.createCompactFormat();
        of.setEncoding("UTF-8");
        XMLWriter writer = new XMLWriter(fw, of);
        writer.write(document);
        writer.flush();
        writer.close();
    }

    //美化输出
    public static void Writer2(Document document) throws IOException {
        FileWriter fw = new FileWriter("D:\\code\\workspace_IdeaUi\\xml_parse\\Dom4jStudent.xml");
        OutputFormat of = new OutputFormat();
        of.setEncoding("UTF-8");
        of.setIndent(true);
        of.setNewlines(true);
        XMLWriter xmlWriter = new XMLWriter(fw, of);
        xmlWriter.write(document);
        xmlWriter.flush();
        xmlWriter.close();
    }

    //便捷美化输出
    public static void Writer3(Document document) throws IOException {
        FileWriter fw = new FileWriter("D:\\code\\workspace_IdeaUi\\xml_parse\\Dom4jStudent.xml");
        OutputFormat of = OutputFormat.createPrettyPrint();
        XMLWriter xmlWriter = new XMLWriter(fw, of);
        xmlWriter.write(document);
        xmlWriter.flush();
        xmlWriter.close();
    }


    //添加操作
    public static void Create(Document document) throws IOException {
        //获取根节点
        Element rootElement = document.getRootElement();
        //在根节点上添加一个子节点
        Element newElement = rootElement.addElement("student");
        //在该新添加的子节点上为指定的属性赋值
        newElement.addAttribute("id", "006");
        newElement.addAttribute("sex","男");
        //在该新添加的子节点上再添加新的子节点
        Element childEle1 = newElement.addElement("name");
        childEle1.setText("代海辉");
        Element childEle2 = newElement.addElement("age");
        childEle2.setText("50");
        Element childEle3 = newElement.addElement("intro");
        childEle3.setText("花心萝卜头");

        //Writer(document);
        //Writer1(document);
        //Writer2(document);
        Writer3(document);
    }

    //删除操作
    public static void Delete(Document document){
        //获取根节点
        Element rootElement = document.getRootElement();
        //通过根节点来获取其所有子节点
        List<Element> elements = rootElement.elements();
        elements.forEach(o->{
            //根据属性名获取属性值
            String id = o.attributeValue("id");
            if ("001".equalsIgnoreCase(id)){
                //通过父节点来删除子节点
                Element parent = o.getParent();
                parent.remove(o);
            }else {
                System.out.println("删除失败。。。");
            }
        });
    }

    //修改操作
    public static void Update(Document document){
        //获取根节点
        Element rootElement = document.getRootElement();
        //获取子节点
        List<Element> elements = rootElement.elements();
        elements.forEach(o->{
            if ("002".equals(o.attributeValue("id"))){
                List<Element> childEle = o.elements();
                childEle.forEach(e1->{
                    String type = e1.getName();
                    if ("name".equals(type)){
                        e1.setText("李煌民");
                    }
                    if ("age".equals(type)){
                        e1.setText("21");
                    }
                    if ("intro".equals(type)){
                        e1.setText("长得帅惹人爱");
                    }
                });
            }
        });
    }

    //查找操作
    public static void Select(Document document){
        //获取根节点
        Element rootElement = document.getRootElement();
        //String name = rootElement.getName();//获得根标签的名字
        //获取到带命名空间的标签名
        QName qName = rootElement.getQName();
        //获得根标签的名字
        String name = qName.getName();
        System.out.print("<" + name);

        //获取根节点的属性
        List attrs = rootElement.attributes();
        if (attrs.size() != 0){
            attrs.forEach(o->{
                Attribute attr = (Attribute) o;
                String attrName = attr.getName();
                String attrValue = attr.getValue();
                System.out.print(attrName + "\"" + attrValue + "\" ");
            });
        }
        System.out.print(">");

        //获取某个节点的所有Element子节点
        //处理根节点的子节点
        List elements = rootElement.elements();
        elements.forEach(o->{
            //该element就是student
            Element element = (Element) o;
            String ele_name = element.getQName().getName();
            System.out.println("<" + ele_name + ">");
            //包含子节点的子节点 ...的所有的文本值 )
            System.out.println(element.getStringValue());

            //获取该节点的所有子节点
            List<Element> childElement = element.elements();
            childElement.forEach(o1->{
                String childName = o1.getQName().getName();
                System.out.print("<" + childName + ">");

                //不递归,将不会获取子元素的文本值
                String text = o1.getText();
                //会递归,这里会获取此节点及其所有子节点的文本值
                //String stringValue = o1.getStringValue();
                System.out.print(text);
                System.out.print("</" + childName + ">");
            });
            System.out.print("</" + ele_name + ">");
        });
        System.out.println("</" + name + ">");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值