从零开始学XML(修订版)

为CV数据集嵌入JSON-LD溯源信息:打造机器可读的“数字身份证” 在数据驱动的计算机视觉和机器学习领域,数据集的规范管理与可信溯源是保障研究可复现性和模型可靠性的基石。传统的数据集管理方式往往依赖README文件等非结构化文档,导致数据集的创建者、版本演变、预处理流程和衍生关系等信息难以被机器自动解析和关联,形成了“数据孤岛”。JSON-LD作为一种基于JSON的轻量级关联数据格式,通过链接到Schema.org、PROV-O等标准本体,能够为数据集赋予明确的语义,构建机器可读的“数字身份证”。其技术价值在于实现了数据溯源信息的结构化与互联,使得数据集的生命周期——包括数 阅读详情

前言

只有光头才能变强。

文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y

什么是XML?

XML:extensiable markup language 被称作可扩展标记语言

XML简单的历史介绍:

为什么我们需要使用XML呢?

640?wx_fmt=png

XML文件就解决了以上的问题了,如果使用XML描述上述图片的关系,是非常简单的!

<?xml version="1.0" encoding="UTF-8" ?><中国>    <北京>        <海淀></海淀>        <丰台></丰台>    </北京>    <湖南>        <长沙></长沙>        <岳阳></岳阳>    </湖南>    <湖北>        <武汉></武汉>        <荆州></荆州>    </湖北></中国>
<中国>
    <北京>
        <海淀></海淀>
        <丰台></丰台>
    </北京>
    <湖南>
        <长沙></长沙>
        <岳阳></岳阳>
    </湖南>
    <湖北>
        <武汉></武汉>
        <荆州></荆州>
    </湖北>
</中国>

XML文件还能使用浏览器打开:

640?wx_fmt=png

我们可以发现XML是可以描述很复杂的数据关系的


XML的用途

①:配置文件(例子:Tomcat的web.xml,server.xml……),XML能够非常清晰描述出程序之间的关系

②:程序间数据的传输,XML的格式是通用的,能够减少交换数据时的复杂性!

③:充当小型数据库,如果我们的数据有时候需要人工配置的,那么XML充当小型的数据库是个不错的选择,程序直接读取XML文件显然要比读取数据库要快呢!


XML的技术架构

XML被设计为“什么都不做”,XML数据或XML文档只用于组织、存储数据,除此之外的数据生成、读取、传送、存取等等操作都与XML本身无关!

于是乎,想要操作XML,就需要用到XML之外的技术了:


XML语法:

文档声明:

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

元素

首先在这里说明一个概念:在XML中元素和标签指的是同一个东西!不要被不同的名称所迷惑了!

元素中需要值得注意的地方:

看起来好像有很多需要值得注意的地方,其实只需要记住:XML的语法是规范的!不要随意乱写!


属性

属性是作为XML元素中的一部分的,命名规范也是和XML元素一样的!

<!--属性名是name,属性值是china--><中国 name="china"></中国>
<中国 name="china">

</中国>

注释

注释和HTML的注释是一样的

<!---->

CDATA

在编写XML文件时,有些内容可能不想让解析引擎解析执行,而是当作原始内容处理。遇到此种情况,可以把这些内容放在CDATA区里,对于CDATA区域内的内容,XML解析程序不会处理,而是直接原封不动的输出

语法:

<![CDATA[    ...内容]]>
]]>

转义字符

对于一些单个字符,若想显示其原始样式,也可以使用转义的形式予以处理。

640?wx_fmt=png

处理指令

处理指令,简称PI (processing instruction)。处理指令用来指挥解析引擎如何解析XML文档内容。

例如:

在XML文档中可以使用xml-stylesheet指令,通知XML解析引擎,应用css文件显示xml文档内容。

<?xml-stylesheet type="text/css" href="1.css"?>
<?xml version="1.0" encoding="UTF-8" ?><?xml-stylesheet type="text/css" href="1.css"?><china>    <guangzhou>        广州    </guangzhou>    <shenzhen>        深圳    </shenzhen></china>
<?xml-stylesheet type="text/css" href="1.css"?>

<china>
    <guangzhou>
        广州
    </guangzhou>
    <shenzhen>
        深圳
    </shenzhen>
</china>
guangzhou{    font-size: 40px;}
}
640?wx_fmt=png

JDK中的XML API

①:JAXP(The Java API For XML Processing):主要负责解析XML

②:JAXB(Java Architecture for XML Binding):主要负责将XML映射为Java对象

什么是XML解析

前面XML章节已经说了,XML被设计为“什么都不做”,XML只用于组织、存储数据,除此之外的数据生成、读取、传送等等的操作都与XML本身无关!

XML解析就是读取XML的数据!


XML解析方式

XML解析方式分为两种:

①:dom(Document Object Model)文档对象模型,是W3C组织推荐解析XML的一种方式

②:sax(Simple API For XML),它是XML社区的标准,几乎所有XML解析器都支持它!

XML解析操作

640?wx_fmt=png

从上面的图很容易发现,应用程序不是直接对XML文档进行操作的,而是由XML解析器对XML文档进行分析,然后应用程序通过XML解析器所提供的DOM接口或者SAX接口对分析结果进行操作,从而间接地实现了对XML文档的访问!

常用的解析器和解析开发包的关系如下所示:

640?wx_fmt=png

为什么有3种开发包?


jaxp

虽然jaxp解析XML的性能以及开发的简易度是没有dom4j好,但是jaxp不管怎么说都是JDK内置的开发包,我们是需要学习的!

DOM解析操作

DOM解析是一个基于对象的API,它把XML的内容加载到内存中,生成与XML文档内容对应的模型!当解析完成,内存中会生成与XML文档的结构与之对应的DOM对象树,这样就能够根据树的结构,以节点的形式对文档进行操作!

简单来说:DOM解析会把XML文档加载到内存中,生成DOM树的元素都是以对象的形式存在的!我们操作这些对象就能够操作XML文档了!

640?wx_fmt=png

既然XML文档的数据是带有关系型的,那么生成的DOM树的节点也是有关系的:

在DOM解析中有几个核心的操作接口:

节点之间的关系图:

640?wx_fmt=png

好的,不跟你们多bb,我们来使用一下Dom的方式解析XML文档吧!

<?xml version="1.0" encoding="UTF-8" ?><china>    <guangzhou >广州</guangzhou>    <shenzhen>深圳</shenzhen>    <beijing>北京</beijing>    <shanghai>上海</shanghai></china>
<china>
    <guangzhou >广州</guangzhou>
    <shenzhen>深圳</shenzhen>
    <beijing>北京</beijing>
    <shanghai>上海</shanghai>
</china>
public class DomParse {    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {        //API规范:需要用一个工厂来造解析器对象,于是我先造了一个工厂!        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();        //获取解析器对象        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();        //获取到解析XML文档的流对象        InputStream inputStream = DomParse.class.getClassLoader().getResourceAsStream("city.xml");        //解析XML文档,得到了代表XML文档的Document对象!        Document document = documentBuilder.parse(inputStream);    }}class DomParse {

    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {

        //API规范:需要用一个工厂来造解析器对象,于是我先造了一个工厂!
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

        //获取解析器对象
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

        //获取到解析XML文档的流对象
        InputStream inputStream = DomParse.class.getClassLoader().getResourceAsStream("city.xml");

        //解析XML文档,得到了代表XML文档的Document对象!
        Document document = documentBuilder.parse(inputStream);

    }
}

遍历

640?wx_fmt=png
public class DomParse {    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {        //API规范:需要用一个工厂来造解析器对象,于是我先造了一个工厂!        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();        //获取解析器对象        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();        //获取到解析XML文档的File对象        InputStream inputStream = DomParse.class.getClassLoader().getResourceAsStream("city.xml");        //解析XML文档,得到了代表XML文档的Document对象!        Document document = documentBuilder.parse(inputStream);        //把代表XML文档的document对象传递进去给list方法        list(document);    }    //我们这里就接收Node类型的实例对象吧!多态!!!    private static void list(Node node) {        //判断是否是元素节点,如果是元素节点就直接输出        if (node.getNodeType() == Node.ELEMENT_NODE) {            System.out.println(node.getNodeName());        }        //....如果没有进入if语句,下面的肯定就不是元素节点了,所以获取到子节点集合        NodeList nodeList = node.getChildNodes();        //遍历子节点集合        for (int i = 0; i < nodeList.getLength(); i++) {            //获取到其中的一个子节点            Node child = nodeList.item(i);            //...判断该子节点是否为元素节点,如果是元素节点就输出,不是元素节点就再获取到它的子节点集合...递归了            list(child);        }    }}class DomParse {

    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {

        //API规范:需要用一个工厂来造解析器对象,于是我先造了一个工厂!
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

        //获取解析器对象
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

        //获取到解析XML文档的File对象
        InputStream inputStream = DomParse.class.getClassLoader().getResourceAsStream("city.xml");

        //解析XML文档,得到了代表XML文档的Document对象!
        Document document = documentBuilder.parse(inputStream);

        //把代表XML文档的document对象传递进去给list方法
        list(document);

    }


    //我们这里就接收Node类型的实例对象吧!多态!!!
    private static void list(Node node) {

        //判断是否是元素节点,如果是元素节点就直接输出
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            System.out.println(node.getNodeName());
        }

        //....如果没有进入if语句,下面的肯定就不是元素节点了,所以获取到子节点集合
        NodeList nodeList = node.getChildNodes();

        //遍历子节点集合
        for (int i = 0; i < nodeList.getLength(); i++) {

            //获取到其中的一个子节点
            Node child = nodeList.item(i);

            //...判断该子节点是否为元素节点,如果是元素节点就输出,不是元素节点就再获取到它的子节点集合...递归了

            list(child);
        }

    }
}
640?wx_fmt=png

查询

现在我要做的就是:读取guangzhou这个节点的文本内容!

private static void read(Document document) {    //获取到所有名称为guangzhou节点    NodeList nodeList = document.getElementsByTagName("guangzhou");    //取出第一个名称为guangzhou的节点    Node node = nodeList.item(0);    //获取到节点的文本内容    String value = node.getTextContent();    System.out.println(value);}

    //获取到所有名称为guangzhou节点
    NodeList nodeList = document.getElementsByTagName("guangzhou");

    //取出第一个名称为guangzhou的节点
    Node node = nodeList.item(0);

    //获取到节点的文本内容
    String value = node.getTextContent();

    System.out.println(value);

}
640?wx_fmt=png

增加

现在我想多增加一个城市节点(杭州),我需要这样做:

private static void add(Document document) {    //创建需要增加的节点    Element element = document.createElement("hangzhou");    //向节点添加文本内容    element.setTextContent("杭州");    //得到需要添加节点的父节点    Node parent = document.getElementsByTagName("china").item(0);    //把需要增加的节点挂在父节点下面去    parent.appendChild(element);}

    //创建需要增加的节点
    Element element = document.createElement("hangzhou");

    //向节点添加文本内容
    element.setTextContent("杭州");

    //得到需要添加节点的父节点
    Node parent = document.getElementsByTagName("china").item(0);

    //把需要增加的节点挂在父节点下面去
    parent.appendChild(element);

}
//获取一个转换器它需要工厂来造,那么我就造一个工厂TransformerFactory transformerFactory = TransformerFactory.newInstance();//获取转换器对象Transformer transformer = transformerFactory.newTransformer();
TransformerFactory transformerFactory = TransformerFactory.newInstance();

//获取转换器对象
Transformer transformer = transformerFactory.newTransformer();
640?wx_fmt=png
640?wx_fmt=png
private static void add(Document document) throws TransformerException {    //创建需要增加的节点    Element element = document.createElement("hangzhou");    //向节点添加文本内容    element.setTextContent("杭州");    //得到需要添加节点的父节点    Node parent = document.getElementsByTagName("china").item(0);    //把需要增加的节点挂在父节点下面去    parent.appendChild(element);    //获取一个转换器它需要工厂来造,那么我就造一个工厂    TransformerFactory transformerFactory = TransformerFactory.newInstance();    //获取转换器对象    Transformer transformer = transformerFactory.newTransformer();    //把内存中的Dom树更新到硬盘中    transformer.transform(new DOMSource(document),new StreamResult("city.xml"));}

    //创建需要增加的节点
    Element element = document.createElement("hangzhou");

    //向节点添加文本内容
    element.setTextContent("杭州");

    //得到需要添加节点的父节点
    Node parent = document.getElementsByTagName("china").item(0);

    //把需要增加的节点挂在父节点下面去
    parent.appendChild(element);

    //获取一个转换器它需要工厂来造,那么我就造一个工厂
    TransformerFactory transformerFactory = TransformerFactory.newInstance();

    //获取转换器对象
    Transformer transformer = transformerFactory.newTransformer();

    //把内存中的Dom树更新到硬盘中
    transformer.transform(new DOMSource(document),new StreamResult("city.xml"));
}
640?wx_fmt=png

刚刚增加的节点是在china节点的末尾处的,现在我想指定增加节点的在beijing节点之前,是这样做的:

private static void add2(Document document) throws TransformerException {    //获取到beijing节点    Node beijing = document.getElementsByTagName("beijing").item(0);    //创建新的节点    Element element = document.createElement("guangxi");    //设置节点的文本内容    element.setTextContent("广西");    //获取到要创建节点的父节点,    Node parent = document.getElementsByTagName("china").item(0);    //将guangxi节点插入到beijing节点之前!    parent.insertBefore(element, beijing);    //将内存中的Dom树更新到硬盘文件中    TransformerFactory transformerFactory = TransformerFactory.newInstance();    Transformer transformer = transformerFactory.newTransformer();    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));}

    //获取到beijing节点
    Node beijing = document.getElementsByTagName("beijing").item(0);

    //创建新的节点
    Element element = document.createElement("guangxi");

    //设置节点的文本内容
    element.setTextContent("广西");

    //获取到要创建节点的父节点,
    Node parent = document.getElementsByTagName("china").item(0);

    //将guangxi节点插入到beijing节点之前!
    parent.insertBefore(element, beijing);

    //将内存中的Dom树更新到硬盘文件中
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));

}
640?wx_fmt=png

删除

现在我要删除的是beijing这个节点!

private static void delete(Document document) throws TransformerException {    //获取到beijing这个节点    Node node = document.getElementsByTagName("beijing").item(0);    //获取到父节点,然后通过父节点把自己删除了    node.getParentNode().removeChild(node);    //把内存中的Dom树更新到硬盘文件中    TransformerFactory transformerFactory = TransformerFactory.newInstance();    Transformer transformer = transformerFactory.newTransformer();    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));}

    //获取到beijing这个节点
    Node node = document.getElementsByTagName("beijing").item(0);

    //获取到父节点,然后通过父节点把自己删除了
    node.getParentNode().removeChild(node);

    //把内存中的Dom树更新到硬盘文件中
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));


}
640?wx_fmt=png

修改

将guangzhou节点的文本内容修改成广州你好

private static void update(Document document) throws TransformerException {    //获取到guangzhou节点    Node node = document.getElementsByTagName("guangzhou").item(0);    node.setTextContent("广州你好");    //将内存中的Dom树更新到硬盘文件中    TransformerFactory transformerFactory = TransformerFactory.newInstance();    Transformer transformer = transformerFactory.newTransformer();    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));}

    //获取到guangzhou节点
    Node node = document.getElementsByTagName("guangzhou").item(0);

    node.setTextContent("广州你好");

    //将内存中的Dom树更新到硬盘文件中
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));


}
640?wx_fmt=png

操作属性

XML文档是可能带有属性值的,现在我们要guangzhou节点上的属性

private static void updateAttribute(Document document) throws TransformerException {    //获取到guangzhou节点    Node node = document.getElementsByTagName("guangzhou").item(0);    //现在node节点没有增加属性的方法,所以我就要找它的子类---Element    Element guangzhou = (Element) node;    //设置一个属性,如果存在则修改,不存在则创建!    guangzhou.setAttribute("play", "gzchanglong");    //如果要删除属性就用removeAttribute()方法    //将内存中的Dom树更新到硬盘文件中    TransformerFactory transformerFactory = TransformerFactory.newInstance();    Transformer transformer = transformerFactory.newTransformer();    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));}

    //获取到guangzhou节点
    Node node = document.getElementsByTagName("guangzhou").item(0);

    //现在node节点没有增加属性的方法,所以我就要找它的子类---Element
    Element guangzhou = (Element) node;

    //设置一个属性,如果存在则修改,不存在则创建!
    guangzhou.setAttribute("play", "gzchanglong");

    //如果要删除属性就用removeAttribute()方法


    //将内存中的Dom树更新到硬盘文件中
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));


}
640?wx_fmt=png

SAX解析

SAX采用的是一种顺序的模式进行访问,是一种快速读取XML数据的方式。当时候SAX解析器进行操作时,会触发一系列事件SAX。采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器

sax是一种推式的机制,你创建一个sax 解析器,解析器在发现xml文档中的内容时就告诉你(把事件推给你). 如何处理这些内容,由程序员自己决定。

当解析器解析到<?xml version="1.0" encoding="UTF-8" standalone="no"?>声明头时,会触发事件。解析到<china>元素头时也会触发事件!也就是说:当使用SAX解析器扫描XML文档(也就是Document对象)开始、结束,以及元素的开始、结束时都会触发事件,根据不同事件调用相对应的方法!

640?wx_fmt=png

首先我们还是先拿到SAX的解析器再说吧!

//要得到解析器对象就需要造一个工厂,于是我造了一个工厂SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();//获取到解析器对象SAXParser saxParse = saxParserFactory.newSAXParser();
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

//获取到解析器对象
SAXParser saxParse = saxParserFactory.newSAXParser();
640?wx_fmt=png
@Overridepublic void startDocument() throws SAXException {    super.startDocument();}@Overridepublic void endDocument() throws SAXException {    super.endDocument();}@Overridepublic void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {    super.startElement(uri, localName, qName, attributes);}@Overridepublic void endElement(String uri, String localName, String qName) throws SAXException {    super.endElement(uri, localName, qName);}@Overridepublic void characters(char[] ch, int start, int length) throws SAXException {    super.characters(ch, start, length);}
public void startDocument() throws SAXException {
    super.startDocument();
}

@Override
public void endDocument() throws SAXException {
    super.endDocument();
}

@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    super.startElement(uri, localName, qName, attributes);
}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
    super.endElement(uri, localName, qName);
}

@Override
public void characters(char[] ch, int start, int length) throws SAXException {
    super.characters(ch, start, length);
}
public static void main(String[] args) throws Exception{    //要得到解析器对象就需要造一个工厂,于是我造了一个工厂    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();    //获取到解析器对象    SAXParser saxParse = saxParserFactory.newSAXParser();    //获取到XML文档的流对象    InputStream inputStream = SAXParse.class.getClassLoader().getResourceAsStream("city.xml");    saxParse.parse(inputStream, new MyHandler());}

    //要得到解析器对象就需要造一个工厂,于是我造了一个工厂
    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

    //获取到解析器对象
    SAXParser saxParse = saxParserFactory.newSAXParser();

    //获取到XML文档的流对象
    InputStream inputStream = SAXParse.class.getClassLoader().getResourceAsStream("city.xml");

    saxParse.parse(inputStream, new MyHandler());

}
public class MyHandler extends 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 {        //如果要解析出节点属性的内容,也非常简单,只要通过attributes变量就行了!        //输出节点的名字!        System.out.println(qName);    }    @Override    public void endElement(String uri, String localName, String qName) throws SAXException {        System.out.println(qName);    }    @Override    public void characters(char[] ch, int start, int length) throws SAXException {        System.out.println(new String(ch,start,length));    }}class MyHandler extends 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 {

        //如果要解析出节点属性的内容,也非常简单,只要通过attributes变量就行了!

        //输出节点的名字!
        System.out.println(qName);
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {

        System.out.println(qName);
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {

        System.out.println(new String(ch,start,length));
    }
}
//定义一个标识量,用于指定查询某个节点的内容boolean flag = false;@Overridepublic void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {    //如果节点名称是guangzhou,我才输出,并且把标识量设置为true    if (qName == "guangzhou") {        System.out.println(qName);        flag = true;    }}@Overridepublic void characters(char[] ch, int start, int length) throws SAXException {    //只有在flag为true的情况下我才输出文本的内容    if (flag == true) {        System.out.println(new String(ch, start, length));    }}@Overridepublic void endElement(String uri, String localName, String qName) throws SAXException {    //在执行到元素的末尾时,不要忘了将标识量改成false    if (qName == "guangzhou" && flag == true) {        System.out.println(qName);        flag = false;    }}
boolean flag = false;

@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

    //如果节点名称是guangzhou,我才输出,并且把标识量设置为true
    if (qName == "guangzhou") {
        System.out.println(qName);
        flag = true;
    }
}


@Override
public void characters(char[] ch, int start, int length) throws SAXException {
    //只有在flag为true的情况下我才输出文本的内容
    if (flag == true) {
        System.out.println(new String(ch, start, length));

    }
}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {

    //在执行到元素的末尾时,不要忘了将标识量改成false
    if (qName == "guangzhou" && flag == true) {
        System.out.println(qName);
        flag = false;

    }
}
640?wx_fmt=png

DOM和SAX解析的区别:

DOM解析读取整个XML文档,在内存中形成DOM树,很方便地对XML文档的内容进行增删改。但如果XML文档的内容过大,那么就会导致内存溢出!

SAX解析采用部分读取的方式,可以处理大型文件,但只能对文件按顺序从头到尾解析一遍,不支持文件的增删改操作

DOM和SAX解析有着明显的差别,什么时候使用DOM或者SAX就非常明了了。


dom4j

Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。

为什么需要有dom4j

因为dom4j不是sun公司的产品,所以我们开发dom4j需要导入开发包


获取dom4j的解析器

//获取到解析器SAXReader saxReader = new SAXReader();//获取到XML文件的流对象InputStream inputStream = DOM4j.class.getClassLoader().getResourceAsStream("1.xml");//通过解析器读取XML文件Document document = saxReader.read(inputStream);
SAXReader saxReader = new SAXReader();

//获取到XML文件的流对象
InputStream inputStream = DOM4j.class.getClassLoader().getResourceAsStream("1.xml");

//通过解析器读取XML文件
Document document = saxReader.read(inputStream);

获取Document对象

我们都知道,Document代表的是XML文档,一般我们都是通过Document对象开始,来进行CRUD(增删改查)操作的!

获取Document对象有三种方式:

①:读取XML文件,获得document对象(这种最常用)

SAXReader reader = new SAXReader();Document document = reader.read(new File("input.xml"));
Document document = reader.read(new File("input.xml"));

②:解析XML形式的文本,得到document对象

String text = "<members></members>";Document document=DocumentHelper.parseText(text);
Document document=DocumentHelper.parseText(text);

③:主动创建document对象.

Document document =DocumentHelper.createDocument();//创建根节点Element root = document.addElement("members");
//创建根节点
Element root = document.addElement("members");

CRUD的重要一句话:

读取XML文档的数据,都是通过Document获取根元素,再通过根元素获取得到其他节点的,从而进行操作!

如果XML的结构有多层,需要一层一层地获取!

查询

@Testpublic void read() throws DocumentException {    //获取到解析器    SAXReader saxReader = new SAXReader();    //获取到XML文件的流对象    InputStream inputStream = dom4j11.class.getClassLoader().getResourceAsStream("1.xml");    //通过解析器读取XML文件    Document document = saxReader.read(inputStream);    //获取得到根节点    Element root = document.getRootElement();    //获取得到name节点    Element name = root.element("name");    //得到了name节点,就可以获取name节点的属性或者文本内容了!    String text = name.getText();    String attribute = name.attributeValue("littleName");    System.out.println("文本内容是:" + text);    System.out.println("属性内容是:" + attribute);}
public void read() throws DocumentException {

    //获取到解析器
    SAXReader saxReader = new SAXReader();

    //获取到XML文件的流对象
    InputStream inputStream = dom4j11.class.getClassLoader().getResourceAsStream("1.xml");

    //通过解析器读取XML文件
    Document document = saxReader.read(inputStream);

    //获取得到根节点
    Element root = document.getRootElement();

    //获取得到name节点
    Element name = root.element("name");

    //得到了name节点,就可以获取name节点的属性或者文本内容了!
    String text = name.getText();

    String attribute = name.attributeValue("littleName");

    System.out.println("文本内容是:" + text);
    System.out.println("属性内容是:" + attribute);

}
<?xml version="1.0" encoding="UTF-8" ?>     <person>    <name littleName="fucheng">zhongfucheng</name>    <age>20</age></person>
     <person>
    <name littleName="fucheng">zhongfucheng</name>
    <age>20</age>
</person>
640?wx_fmt=png
//获取得到根节点Element root = document.getRootElement();//一层一层地获取到节点Element element = root.element("guangdong").element("guangzhou").element("luogang");String value = element.getText();System.out.println(value);
Element root = document.getRootElement();

//一层一层地获取到节点
Element element = root.element("guangdong").element("guangzhou").element("luogang");

String value = element.getText();

System.out.println(value);
640?wx_fmt=png

增加

在DOM4j中要对内存中的DOM树写到硬盘文件中,也是要有转换器的支持的!

dom4j提供了XMLWriter供我们对XML文档进行更新操作,一般地创建XMLWriter的时候我们都会给出两个参数,一个是Writer,一个是OutputFormat

640?wx_fmt=png

这个OutputFormat有什么用的呢?其实就是指定回写XML的格式和编码格式。细心的朋友会发现,上面我们在jaxp包下使用dom解析的Transformer类,把内存中的DOM树更新到文件硬盘中,是没有格式的!不信倒回去看看!这个OutputFormat就可以让我们更新XML文档时也能带有格式!

//创建带有格式的对象OutputFormat outputFormat = OutputFormat.createPrettyPrint();//设置编码,默认的编码是gb2312,读写的编码不一致,会导致乱码的!outputFormat.setEncoding("UTF-8");//创建XMLWriter对象XMLWriter xmlWriter = new XMLWriter(new FileWriter("2.xml"), outputFormat);//XMLWriter对象写入的是documentxmlWriter.write(document);//关闭流xmlWriter.close();
OutputFormat outputFormat = OutputFormat.createPrettyPrint();

//设置编码,默认的编码是gb2312,读写的编码不一致,会导致乱码的!
outputFormat.setEncoding("UTF-8");

//创建XMLWriter对象
XMLWriter xmlWriter = new XMLWriter(new FileWriter("2.xml"), outputFormat);

//XMLWriter对象写入的是document
xmlWriter.write(document);

//关闭流
xmlWriter.close();
@Testpublic void add() throws Exception {    //获取到解析器    SAXReader saxReader = new SAXReader();    //获取到XML文件的流对象    InputStream inputStream = dom4j11.class.getClassLoader().getResourceAsStream("1.xml");    //通过解析器读取XML文件    Document document = saxReader.read(inputStream);    //创建出新的节点,为节点设置文本内容    Element newElement = DocumentHelper.createElement("name");    newElement.setText("ouzicheng");    //获取到根元素    Element root = document.getRootElement();    //把新创建的name节点挂在根节点下面    root.add(newElement);    //创建带有格式的对象    OutputFormat outputFormat = OutputFormat.createPrettyPrint();    //设置编码,默认的编码是gb2312,读写的编码不一致,会导致乱码的!    outputFormat.setEncoding("UTF-8");    //创建XMLWriter对象    XMLWriter xmlWriter = new XMLWriter(new FileWriter("2.xml"), outputFormat);    //XMLWriter对象写入的是document    xmlWriter.write(document);    //关闭流    xmlWriter.close();}
public void add() throws Exception {

    //获取到解析器
    SAXReader saxReader = new SAXReader();

    //获取到XML文件的流对象
    InputStream inputStream = dom4j11.class.getClassLoader().getResourceAsStream("1.xml");

    //通过解析器读取XML文件
    Document document = saxReader.read(inputStream);

    //创建出新的节点,为节点设置文本内容
    Element newElement = DocumentHelper.createElement("name");
    newElement.setText("ouzicheng");

    //获取到根元素
    Element root = document.getRootElement();

    //把新创建的name节点挂在根节点下面
    root.add(newElement);

    //创建带有格式的对象
    OutputFormat outputFormat = OutputFormat.createPrettyPrint();

    //设置编码,默认的编码是gb2312,读写的编码不一致,会导致乱码的!
    outputFormat.setEncoding("UTF-8");

    //创建XMLWriter对象
    XMLWriter xmlWriter = new XMLWriter(new FileWriter("2.xml"), outputFormat);

    //XMLWriter对象写入的是document
    xmlWriter.write(document);

    //关闭流
    xmlWriter.close();


}
640?wx_fmt=png

在指定的位置增加节点!现在我想的就是在age属性前面添加节点!

//创建一个新节点Element element = DocumentHelper.createElement("name");element.setText("ouzciheng");//获取得到person下所有的节点元素!List list = document.getRootElement().elements();//将节点添加到指定的位置上list.add(1, element);
Element element = DocumentHelper.createElement("name");
element.setText("ouzciheng");

//获取得到person下所有的节点元素!
List list = document.getRootElement().elements();

//将节点添加到指定的位置上
list.add(1, element);
640?wx_fmt=png


修改

//获取得到age元素Element age = document.getRootElement().element("age");age.setText("9999");
Element age = document.getRootElement().element("age");
age.setText("9999");
640?wx_fmt=png

删除

//获取得到age节点Element age = document.getRootElement().element("age");//得到age节点的父节点,使用父节点的remove删除age节点!age.getParent().remove(age);
Element age = document.getRootElement().element("age");

//得到age节点的父节点,使用父节点的remove删除age节点!
age.getParent().remove(age);
640?wx_fmt=png

XPATH

什么是XPATH

XPath 是一门在 XML 文档中查找信息的语言。XPath 用于在 XML 文档中通过元素和属性进行导航。

为什么我们需要用到XPATH

上面我们使用dom4j的时候,要获取某个节点,都是通过根节点开始,一层一层地往下寻找,这就有些麻烦了!

如果我们用到了XPATH这门语言,要获取得到XML的节点,就非常地方便了!


快速入门

使用XPATH需要导入开发包jaxen-1.1-beta-7,我们来看官方的文档来入门吧。

640?wx_fmt=png
640?wx_fmt=png
640?wx_fmt=png
//直接获取到luogang节点org.dom4j.Node node =  document.selectSingleNode("//luogang");//获取节点的内容String value = node.getText();System.out.println(value);
org.dom4j.Node node =  document.selectSingleNode("//luogang");

//获取节点的内容
String value = node.getText();

System.out.println(value);
640?wx_fmt=png

获取什么类型的节点,XPATH的字符串应该怎么匹配,查文档就知道了,这里就不再赘述了。!


最后

乐于输出干货的Java技术公众号:Java3y。公众号内有200多篇原创技术文章、海量视频资源、精美脑图,不妨来关注一下!

640?wx_fmt=jpeg

有帮助?好看!转发!640
Ubuntu上LEMP部署WordPress完整指南:性能、安全与高并发实战 WordPress作为全球占比超43%的内容管理系统,其生产环境部署已从‘能用’迈向‘稳、快、安’的工程标准。LEMP架构(Linux+Nginx+MySQL+PHP)凭借Nginx事件驱动模型与PHP-FPM进程池协同机制,在高并发场景下显著优于传统LAMP,实测QPS提升2.3倍、内存占用下降41%。Ubuntu 22.04 LTS因长期支持、软件版本契合(Nginx 1.18+/PHP 8.1/MySQL 8.0)及丰富运维生态,成为WordPress部署事实上的黄金基线。本文聚焦真实建站全流程——从 阅读详情

相关推荐

全面掌握XML:初学者必备手册

本文还有配套的精品资源,点击获取 简介:XML是一种用于数据标记的语言,广泛应用于互联网数据交换和应用程序间的数据共享。本手册将引导初学者学习XML的基础知识、命名规则、文档类型定义(DTD)、XML Schema、命名空间、处理指令、实体、解析方法、XPath、XSLT以及XML在Web服务中的应用和验证过程。通过理论知识和实践练习相结合的方式,初学者能够快速入门并理解X...

weixin_35364187的博客 1886

零基础小白如何自学XML?

要从零开始自学XML,可以按照以下步骤:了解XML的基本概念:学习XML语法:实践编写简单的XML文档: 学习如何验证XML:练习解析XML:参考资料:逐步通过实践和小项目来加深理解,逐渐掌握XML的高级特性。例如: DTD(文档类型定义): XML Schema(XSD):示例: XPath:XSLT(可扩展样式表语言转换):XML与JSON的转换:小项目建议:进阶项目:通过系统地学习和实践,逐步掌握XML的基本语法、高级功能、实际应用以及与其他技术的结合

小宝哥Code的专栏 1079

Android-EasyFlipView:快速实现翻转视图的实用库

新手常犯的错误是直接写:结果 IDE 标红,提示属性找不到。原因很简单:你没声明xmlns:app!正确姿势:-- 必须 -->这里的res-auto会自动映射到你当前的应用包名下查找 attrs,非常智能。🤫 私藏技巧:如果属性不生效,试试 Build → Clean Project 再 Sync。有时候你只想让某个按钮触发翻转,而不是整张卡片都响应。

weixin_31486261的博客 358

XML快速入门

主要简单概述了什么是xml,以及如何创建xml,并在java中解析xml

smilehjl 631

Matlab TreeBagger实战:用随机森林预测房价的5个关键步骤(附完整代码)

本文详细介绍了使用Matlab的TreeBagger工具包构建随机森林模型预测房价的完整流程。通过波士顿房价数据集实战,涵盖数据预处理、模型构建、参数调优、特征重要性分析及高级应用(如分位数回归)等5个关键步骤,并附有完整代码,帮助读者快速掌握这一强大的回归分析工具。

ol789012的博客 444

Protege本体建模实战:从零构建电影知识图谱并导入Neo4j

本体建模是知识图谱构建的基石,通过类、属性、实例和约束系统描述领域知识,为数据提供可复用的语义骨架。OWL作为本体描述语言的标准,配合Protege工具可实现可视化建模,并借助推理机验证逻辑一致性,提升模型可靠性。在工程落地中,本体模型常需导入图数据库如Neo4j,以支持高效的关联查询与业务应用。本文以影视领域为背景,完整演示Protege中定义类层级、创建对象/数据属性、填充实例,以及导出OWL文件并通过Python脚本转换为Neo4j节点与关系的全过程,同时梳理命名空间、匿名节点、编码等易踩坑点,帮助读

weixin_29047545的博客 281

从零开始写一个XML解析-01简单介绍

MyXML0. 前言1. TinyXML的大体逻辑1.1 从测试开始1.2 逻辑 0. 前言 这算是从零开始的第二个系列了。上一次是从零开始写日志01,从零开始写日志2。这次阅读了TinyXML的源码(Ps:我看的是1,TinyXML2大概使用过)想着就开始了这个系列的第二部。 1. TinyXML的大体逻辑 1.1 从测试开始 这里简单介绍下自己是怎么阅读源码的。 阅读源码时候,切忌不要一上来...

心灵迷宫 285

SAP生产版本导入避坑大全:从‘黄灯’到‘绿灯’,详解CM_FV_MKAL_CONSISTENCY_CHECK检查函数

本文深入解析SAP生产版本导入过程中的常见问题,特别是通过`CM_FV_MKAL_CONSISTENCY_CHECK`检查函数从‘黄灯’异常到‘绿灯’正常的修复方法。涵盖静态与动态校验机制、典型异常场景诊断及批量导入最佳实践,帮助SAP运维人员高效解决生产版本管理难题。

weixin_30568591的博客 387

Java从零开始 第15讲 网络编程,XML和JSON

这里写目录标题网络编程TCP的网络编程多线程网络编程转载请注明出处 网络编程 在本讲之前,我们所有编写的程序都是单机运行的,并没有任何需要网络的部分,而现在让我们学习运用网络的编程 在学习代码之前,让我们先学习两个概念,协议(protocol)和套接字(socket) 协议是端到端通信需要遵循的规矩,你不需要具体理解协议的内容,你只需要明白协议是用于约束信息在网络上传输的东西,就像是交警一样 而套接字,是端到端通信的端点,是网络驱动提供给应用程序编程的一种接口,一种标准,一种机制,当我们想要通过网络传输或者

CheakccL的博客 438

10分钟学会工程领域Hypermesh与Abaqus联立处理大量铆钉连接简化做法

铆钉连接是一种可靠且高强度的机械连接方式,广泛应用于多个领域。但是,工程结构上铆钉连接往往以较大的数量出现,若按照常规的一个个去选择生成,处理1个铆钉连接点需要1分钟来算,300个铆钉需要5个小时,耗费大量的时间成本。给出了一种高效处理铆钉连接的方法,提升效率50倍以上。

qq_34933927的博客 1615

【四足机器人项目实战】四足机器人运动学、动力学模型

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录系列文章目录前言一、四足机器人实际模型的物理难点二、四足机器人运动学模型1.方法一:DH法建立运动学模型(1)运动学建模构型方法(2)运动学模型描述方法1、基于DH法四足机器人单腿运动学模型公式推导(0)DH法科普1)原理2)实现过程3)评价(1)四足机器人的建模规则、坐标系定义及实物参数确定1)标准Denavit-Hartenberg法建模规则2)单腿运动学模型坐标系定义示意图及简化模型3)

qq_35635374的博客 1万+

dom4j生成xml_从零开始学XML(修订版)

前言只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y什么是XML?XML:extensiable markup language 被称作可扩展标记语言XML简单的历史介绍:gml->sgml->html->xmlgml(通用标记语言)–在不同的机器进行通信的数据规范sgml(标准通...

weixin_39951112的博客 379

ABAP CDS 和 HANA SQL 的关系

摘要: ABAP CDS与HANA SQL既有紧密联系又有本质区别。ABAP CDS作为语义数据建模框架,在SQL基础上扩展了业务语义层,通过注解(annotations)、关联关系(associations)等机制为数据附加业务含义,并支持权限控制、客户端处理等ABAP平台特性。虽然CDS实体最终会转换为HANA数据库对象执行,但它并非简单的SQL封装,而是构建了独立于数据库的语义模型。二者在数据库执行层深度融合,ABAP CDS通过代码下推技术将计算任务优化到HANA层完成。实际开发中应优先使用ABAP

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

xml 属性value换行显示_从零开始学XML(修订版)

前言只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y什么是XML?XML:extensiable markup language 被称作可扩展标记语言XML简单的历史介绍:gml->sgml->html->xmlgml(通用标记语言)–在不同的机器进行通信的数据规范sgml(标准通...

weixin_31541755的博客 1423

人工智能_大模型095_Web版003_deepseek R1本地安装_私有化部署_支持RAG_调用HTTPAPI做自己的AI应用_安装RagFlow以及使用_---人工智能工作笔记0240

这里的一定要注意,是资源不够用了,可以点击ragflow-server左边的小绿点,查看 结果。注意去把内存改成10G把至少,我这里改成了10G,因为电脑一共就16G,再试试吧.可以看日志,就显示的是没有连接上mysql,结果我一看,mysql,根本没启动.然后下面选择general就可以了,然后点击确定,然后再去点击。手动去启动,然后再去试试,注意,内存这里给8G太小了还是.调成8G了,然后硬盘大了大了一些换成50G了,然后。点击系统模型设置可以看到,选择聊天模型就可以了,

添柴程序猿的专栏 447

YoloV8优化:感受野注意力卷积运算(RFAConv),效果秒杀CBAM和CA等 | 即插即用系列

感受野注意力卷积运算(RFAConv),解决卷积块注意力模块(CBAM)和协调注意力模块(CA)只关注空间特征,不能完全解决卷积核参数共享的问题

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 4264

将xml转成json_从零开始学JSON(修订版)

前言只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y什么是JSONJSON:JavaScript Object Notation 【JavaScript 对象表示法】JSON 是存储和交换文本信息的语法。类似 XML。JSON采用完全独立于任何程序语言的文本格式,使JSON成为理想的数据交换语言S为...

weixin_42356162的博客 159

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

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

从零开始学JSON(修订版)

前言只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y什么是JSONJSON:Ja...

3y 501

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

javascript json_从零开始学JSON(修订版)

什么是JSONJSON:JavaScript Object Notation 【JavaScript 对象表示法】JSON 是存储和交换文本信息的语法。类似 XML。JSON采用完全独立于任何程序语言的文本格式,使JSON成为理想的数据交换语言S为什么需要JSON提到JSON,我们就应该和XML来进行对比。XML也是一种存储和交换文本信息的手段。那么JSON好在哪里呢??JSON 比 XML 更小...

weixin_39735247的博客 134

json解析数组 nlohmann_从零开始学JSON(修订版)

什么是JSONJSON:JavaScript Object Notation 【JavaScript 对象表示法】JSON 是存储和交换文本信息的语法。类似 XML。JSON采用完全独立于任何程序语言的文本格式,使JSON成为理想的数据交换语言S为什么需要JSON提到JSON,我们就应该和XML来进行对比。XML也是一种存储和交换文本信息的手段。那么JSON好在哪里呢??JSON 比 XML 更小...

weixin_39691968的博客 373

六一限定|零基础无压力!10岁到60岁都能轻松看懂的编程好书推荐

最简单易懂的算法教程,像读小说一样轻松。全方位解读人工智能的来龙去脉,几乎覆盖人工智能学科的所有领域,包括人工智能的起源、自动定理证明、专家系统、神经网络、自然语言处理、遗传算法、深度学习、强化学习、超级智能、哲学问题和未来趋势等,以宏阔的视野和生动的语言,对人工智能进行了全面回顾和深度点评。豆瓣评分 9.1,蹲马桶就能看懂的网络基础知识,本书以探索之旅的形式,从在浏览器中输入网址开始,一路追踪了到显示出网页的内容为止的整个过程,以图配文,讲解了网络的全貌,并重点介绍了实际的网络设备和软件是如何工作的。

图灵教育 4361

开源中国Android客户端部署与发布:构建流程与版本管理最佳实践

想要快速掌握开源中国Android客户端的部署与发布流程吗?本文为您提供完整的构建流程与版本管理最佳实践指南,帮助您从零开始构建和发布这款优秀的开源Android应用。开源中国Android客户端是一个功能丰富的社区应用,包含了资讯浏览、软件库、问答社区、动弹分享等核心功能,采用GPL授权协议,让开发者可以自由地学习和改进。 ## 📱 项目概述与准备工作 开源中国Android客户端是一个基

gitblog_01069的博客 666

基于MCP协议构建欧盟金融数据AI Agent:从协议原理到实战开发

Model Context Protocol(MCP)作为一种标准化协议,其核心原理是为大型语言模型提供安全、统一的外部工具和数据调用接口。该协议通过定义标准化的JSON-RPC通信机制,在AI模型与外部系统间建立安全边界,解决了不同模型工具调用格式不兼容的问题,具有重要的技术价值。在工程实践中,MCP服务器常被用于封装特定领域的专业能力,例如金融数据查询与合规分析。通过将复杂的非结构化数据(如法规文档、市场数据)封装成模型可调用的标准化工具,开发者能够快速构建垂直领域的AI应用。本文以构建欧盟金融数据MC

weixin_42676876的博客 520

法律文书助手:OpenClaw调用Qwen3.5-9B生成合规合同草案

本文介绍了如何在星图GPU平台上自动化部署Qwen3.5-9B镜像,构建本地化法律文书助手。该方案通过OpenClaw调用Qwen3.5-9B模型,可快速生成合规合同草案,并具备风险点智能标注、版本对比等功能,特别适用于需要严格数据隐私保护的合同起草场景。

weixin_28771751的博客 403
上一篇: 神经网络浅讲:从神经元到深度学习
下一篇: 从零开始学JSON(修订版)
Java3y
Java3y 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 509原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值