Java 使用dom4j进行XML解析

1、XML解析(dom4j)

1.1 读取XML文档

// 从文件读取XML,输入文件名,返回XML文档
public Document read(String fileName) throws MalformedURLException, DocumentException {
    
    
   SAXReader reader = new SAXReader();
   Document document = reader.read(new File(fileName));
   return document;
}

1.2 获取ROOT节点

public Element getRootElement(Document doc){
    
    
    return doc.getRootElement();
}

1.3 遍历XML树

1.3.1 列举3中遍历方法:
1.3.1.1 枚举(Iterator)
// 枚举所有子节点
for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
    
    
   Element element = (Element) i.next();
   // 业务逻辑
}
// 枚举名称为foo的节点
for ( Iterator i = root.elementIterator(foo); i.hasNext();) {
    
    
   Element foo = (Element) i.next();
   // 业务逻辑
}
// 枚举属性
for ( Iterator i = root.attributeIterator(); i.hasNext(); ) {
    
    
   Attribute attribute = (Attribute) i.next();
   // 业务逻辑
}

1.3.1.2 递归
public void treeWalk() {
    
    
    Document document = read("XML文件路径");
    treeWalk(getRootElement(document));
}
public void treeWalk(Element element) {
    
    
    for (int i = 0, size = element.nodeCount(); i < size; i++)     {
    
    
        Node node = element.node(i);
        if (node instanceof Element) {
    
    
            treeWalk((Element) node);
        } else {
    
     // 业务逻辑
        }
    }
}
1.3.1.3 Visitor模式
Visitor是自动遍历所有子节点的。如果是root.accept(MyVisitor),将遍历子节点
1、定义一个类继承VisitorSupport(实现了Visitor接口)

public class MyVisitor extends VisitorSupport {
    
    

    public MyVisitor() {
    
    
    }

    @Override
    public void visit(Document document) {
    
    
        System.out.println("visit-document = [" + document.asXML() + "]");
    }

    @Override
    public void visit(DocumentType documentType) {
    
    
        super.visit(documentType);
    }

    @Override
    public void visit(Element node) {
    
    
        // isTextOnly() : 可以对一个Element对象调用isTextOnly()方法判断它是否含有text
        if (node.isTextOnly()) {
    
    
            // 含有text
            System.out.println(node.getName() +" "+":"+" "+ node.getText());
        } else {
    
    
            // 存在子节点
            System.out.println("node = [" + node.getName() + "]");
        }
    }

    @Override
    public void visit(Attribute node) {
    
    
        super.visit(node);
    }

    @Override
    public void visit(CDATA node) {
    
    
        super.visit(node);
    }

    @Override
    public void visit(Comment node) {
    
    
        super.visit(node);
    }

    @Override
    public void visit(Entity node) {
    
    
        super.visit(node);
    }

    @Override
    public void visit(Namespace namespace) {
    
    
        super.visit(namespace);
    }

    @Override
    public void visit(ProcessingInstruction node) {
    
    
        super.visit(node);
    }

    @Override
    public void visit(Text node) {
    
    
        super.visit(node);
    }
}

2、调用visit方法
public static void main(String[] args) throws DocumentException {
    
    
        MyVisitor myVisitor = new MyVisitor();

        String resSucc = "<result><MSG><MSG><array><AAC>*****</AAC><AAE>****</AAE><AAA>*</AAA><AAC>*</AAC><AAC>***</AAC><AAC>********</AAC><AAC>******</AAC></array></MSG><SUCCESS>****</SUCCESS></MSG><SUCCESS>****</SUCCESS></result>";
    	
    	// String转XML
        Document document = DocumentHelper.parseText(resSucc);
    	// 自动遍历子节点
        document.accept(myVisitor);
    	System.out.println("=================================");

        Element rootElement = document.getRootElement();
    	// 自动遍历子节点
        rootElement.accept(myVisitor);
    }

3、执行结果:
visit-document = [<?xml version="1.0" encoding="UTF-8"?>
<result><MSG><MSG><array><AAC>*****</AAC><AAE>****</AAE><AAA>*</AAA><AAC>*</AAC><AAC>***</AAC><AAC>********</AAC><AAC>******</AAC></array></MSG><SUCCESS>****</SUCCESS></MSG><SUCCESS>****</SUCCESS></result>]
node = [result]
node = [MSG]
node = [MSG]
node = [array]
AAC : *****
AAE : ****
AAA : *
AAC : *
AAC : ***
AAC : ********
AAC : ******
SUCCESS : ****
SUCCESS : ****
=================================
node = [result]
node = [MSG]
node = [MSG]
node = [array]
AAC : *****
AAE : ****
AAA : *
AAC : *
AAC : ***
AAC : ********
AAC : ******
SUCCESS : ****
SUCCESS : ****

之所以会打印两遍子节点的信息,是因为document.accept(myVisitor)中调用了Element的accpt()方法,即rootElement.accept(myVisitor)

/** 
 *还可以使用内部类的方式调用Visitor,由于自定义的Visitor是需要继承VisitorSupport类,而VisitorSupport  是实现的Visitor接口,所以这里直接用内部类的形式调用visit()方法:
 */

String text = "<skills>\n" +
    "<!--第一个技能-->\n" +
    "<skill name=\"独孤九剑\">\n" +
    "<info>为独孤求败所创,变化万千,凌厉无比。其传人主要有风清扬、令狐冲。</info>\n" +
    "</skill>\n" +
    "<skill name=\"葵花宝典\">\n" +
    "<info>宦官所创,博大精深,而且凶险至极。练宝典功夫时,首先要自宫净身。</info>\n" +
    "</skill>\n" +
    "<skill name=\"北冥神功\">\n" +
    "<info>逍遥派的顶级内功之一,能吸人内力转化为自己所有,威力无穷。</info>\n" +
    "</skill>\n" +
    "</skills>";
Document document1 = DocumentHelper.parseText(text);
Element rootElement1 = document1.getRootElement();
Element skill = rootElement1.element("skill");
skill.accept(new Visitor() {
    
    
    @Override
    public void visit(Document document) {
    
    

    }

    @Override
    public void visit(DocumentType documentType) {
    
    

    }

    @Override
    public void visit(Element element) {
    
    
        System.out.println("element = [" + element.asXML() + "]");
    }

    @Override
    public void visit(Attribute attribute) {
    
    

    }

    @Override
    public void visit(CDATA cdata) {
    
    

    }

    @Override
    public void visit(Comment comment) {
    
    

    }

    @Override
    public void visit(Entity entity) {
    
    

    }

    @Override
    public void visit(Namespace namespace) {
    
    

    }

    @Override
    public void visit(ProcessingInstruction processingInstruction) {
    
    

    }

    @Override
    public void visit(Text text) {
    
    

    }
});

// 打印内容:
// element = [<skill name="独孤九剑">
// <info>为独孤求败所创,变化万千,凌厉无比。其传人主要有风清扬、令狐冲。</info>
// </skill>]
// element = [<info>为独孤求败所创,变化万千,凌厉无比。其传人主要有风清扬、令狐冲。</info>]

1.4 XPath支持

selectNodes语法:

String resSucc = "<result><MSG><MSG name=\"测试\"><array><AAC>*****</AAC><AAE>****</AAE><AAA>*</AAA><AAC>*</AAC><AAC>***</AAC><AAC>********</AAC><AAC>******</AAC></array></MSG><SUCCESS>****</SUCCESS></MSG><SUCCESS>****</SUCCESS></result>";

// String转XML
Document document = DocumentHelper.parseText(resSucc);
// 获取根节点
Element rootElement = document.getRootElement();

// 1、selectNodes("MSG") :从当前节点的子节点中选择名称为 result 的节点。
List<Node> nodes = rootElement.selectNodes("MSG");
nodes.forEach((node -> {
    
    
    System.out.println("node = [" + node.getName() + "]");
}));

// 2、selectNodes("/MSG") :从根节点的子节点中选择名称为 result 的节点。
nodes = rootElement.selectNodes("/MSG");
nodes.forEach((node -> {
    
    
    System.out.println("/node = [" + node.getName() + "]");
}));

// 3、selectNodes("//MSG") :从任意位置的节点上选择名称为 result 的节点
nodes = rootElement.selectNodes("//MSG");
nodes.forEach((node -> {
    
    
    System.out.println("//node = [" + node.getName() + "]");
}));

// 4、selectNodes(".") :选择当前节点。
nodes = rootElement.selectNodes(".");
nodes.forEach((node -> {
    
    
    System.out.println(".node = [" + node.getName() + "]");
}));

// 5、selectNodes("..") :选择当前节点的父节点。
nodes = rootElement.selectNodes("..");
nodes.forEach((node -> {
    
    
    System.out.println("..node = [" + node.getName() + "]");
}));

// 6、selectNodes("//MSG[@name]") :在 selectNodes("//MSG") 的基础上,增加了一个限制,就是要求拥有 name 属性。
nodes = rootElement.selectNodes("//MSG[@name]");
nodes.forEach((node -> {
    
    
    System.out.println("[@name]node = [" + node.getName() + "]");
}));

// 7、selectNodes("//MSG[@name='测试']") :在 selectNodes("//MSG") 的基础上,electNodes("//item[@name]") 的基础上,增加了一个限制,就是要求 name 属性值为 测试。注意语法中有引号;如果没有引号,则表示是数字类型,对于数字类型可以使用大于号、小于号等。
nodes = rootElement.selectNodes("//MSG[@name='测试']");
nodes.forEach((node -> {
    
    
    System.out.println("[@name='测试']node = [" + node.getName() + "]");
}));

// 8、selectSingleNodes("MSG") :只拿第一个MSG节点。
nodes = rootElement.selectSingleNodes("MSG");
nodes.forEach((node -> {
    
    
    System.out.println("node = [" + node.getName() + "]");
}));

1.5 字符串与XML相互转换

// XML转字符串
Document document = ...;
String text = document.asXML();

// 字符串转XML
String text = James ;
Document document = DocumentHelper.parseText(text);

1.6 创建XML

public static void main(String[] args) {
    
    
    	// 创建文档
        Document document = DocumentHelper.createDocument();
    	// 创建根节点
        Element root = document.addElement("root");
        root
                // 当前节点下添加子节点
                .addElement("author")
                // 添加属性
                .addAttribute("name", "James")
                .addAttribute("location", "UK")
                // 添加文本内容
                .addText("James Strachan");
        root
                .addElement("author")
                .addAttribute("name", "Bob")
                .addAttribute("location", "US")
                .addText("Bob McWhirter");
        System.out.println("root:\n" + root.asXML() + "]");
    }

执行结果:
<root><author name="James" location="UK">James Strachan</author><author name="Bob" location="US">Bob McWhirter</author></root>

1.7 文件输出

此处代码接上一节代码:

System.out.println("文件输出准备······");
/**
 * FileOutputStream:字节流,通常用于读写原始字节数据,如图像;可以将文件转成字节数组;读取单位为一个子节
 */
try {
    
    
    OutputFormat format = OutputFormat.createPrettyPrint();
    format.setEncoding("UTF-8");
    XMLWriter xmlWriter = new XMLWriter(new  FileOutputStream("C:\\Users\\Administrator\\Desktop\\CreateXml" +
                                                             ".xml"), format);
    // 如果输出整个xml文档,则会带上xml头<?xml version="1.0" encoding="UTF-8"?>
    //            xmlWriter.write(rootDocument);
    // 如果只输出根节点部分,则不会带xml头
    xmlWriter.write(root);
    xmlWriter.close();
} catch (Exception e) {
    
    
    System.out.println("文件输出失败:" + e.getMessage());
    throw e;
}
System.out.println("文件输出完成\n");

/**
 * FileWriter:字符流,通常用于读写文本数据;读取单位为一个字符,可能是一个字节,也可能是两个字节
 */
try {
    
    
    OutputFormat format = OutputFormat.createPrettyPrint();
    format.setEncoding("UTF-8");
    XMLWriter xmlWriter = new XMLWriter(new FileWriter(new  File("C:\\Users\\Administrator\\Desktop\\CreateXml2.xml")), format);
    // 如果输出整个xml文档,则会带上xml头<?xml version="1.0" encoding="UTF-8"?>
    //            xmlWriter.write(rootDocument);
    // 如果只输出根节点部分,则不会带xml头
    xmlWriter.write(root);
    xmlWriter.close();
} catch (Exception e) {
    
    
    System.out.println("文件输出失败:" + e.getMessage());
    throw e;
}

System.out.println("输出控制台开始");
try {
    
    
    OutputFormat format = OutputFormat.createPrettyPrint();
    format.setEncoding("UTF-8");
    XMLWriter writer = new XMLWriter(System.out, format);
    writer.write(root);
    writer.flush();
} catch (Exception e) {
    
    
    System.out.println("文件输出失败:" + e.getMessage());
    throw e;
}
System.out.println("\n输出控制台完成");

1.8 xml节点解析方法

1.8.1 selectNodes() 和 selectSingleNode()
此处代码接1.6节代码:
    
root.selectNodes("author").forEach((ele) -> {
    
    
    // 查找根节点下的所有author节点并打印节点名称
    System.out.println("eleName = [" + ele.getName() + "]");
});
// 打印内容:
// name = [author] - value = [James Strachan]
// name = [author] - value = [Bob McWhirter]

Node author = root.selectSingleNode("author");
// 获取第一个author节点中的内容
System.out.println("node = [" + author.getText() + "]");
// 打印内容:
// node-value = [James Strachan]

// 获取当前节点的路径
System.out.println("node-path = [" + author.getPath() + "]");
// 打印内容:
// node-path = [/root/author]

1.8.2 element() 和 elements()
/**
 * element() : 获取当前节点下的节点
 * elements() :获取当前节点下的子节点,装载到list并返回,可在此方法上调用size获取节点数
 */

此示例接1.6节代码:
// 获取跟节点下的节点并打印:
root.elements().forEach((ele) -> {
    
    
    System.out.println("eleName = [" + ele.getName() + "]");
});
// 打印内容:
// eleName = [author]
// eleName = [author]

// 获取根节点下的所有author节点并打印:
root.elements("author").forEach((ele) -> {
    
    
    System.out.println("elements = [" + ele.getName() + "]");
});
// elements = [author]
// elements = [author]


String result = "<result><MSG><MSG><array><AAC>**</AAC><AAE>*****</AAE></array></MSG></MSG></result>";
Document doc = DocumentHelper.parseText(result);
Element rootElement = doc.getRootElement();
// 获取根节点下的MSG节点,继续获取MSG节点下的MSG节点并返回里面的节点数量
int count = rootElement.element("MSG").element("MSG").elements().size();
1.8.3 setName()
// 修改节点名称:
rootElement.element("MSG").element("MSG").setName("ERRMSG");
1.8.4 getText() 和 getStringValue()
String resSucc = "<result><MSG><MSG name=\"测试\"><array><AAC>*****</AAC><AAE>****</AAE><AAA>*</AAA><AAC>*</AAC><AAC>***</AAC><AAC>********</AAC><AAC>******</AAC></array></MSG><SU>****</SU></MSG><SU>****</SU></result>";

// String转XML
Document document = DocumentHelper.parseText(resSucc);
// 获取当前节点下所有文本内容
System.out.println("StringValue = [" + document.getStringValue() + "]");
// 如果当前节点下是文本则返回文本,如果当前节点下还是节点则返回空值
System.out.println("Text = [" + document.getText() + "]");

// 打印内容:
// StringValue = [************************************]
// Text = [] 
1.8.5 isTextOnly()
// 判断Element对象是否含有text文本数据
@Override
public void visit(Element node) {
    
    
    // isTextOnly() : 可以对一个Element对象调用isTextOnly()方法判断它是否含有text
    if (node.isTextOnly()) {
    
    
        // 含有text
        System.out.println(node.getName() +" "+":"+" "+ node.getText());
    } else {
    
    
        // 存在子节点
        System.out.println("node = [" + node.getName() + "]");
    }
}
1.8.6 自定义递归方法遍历所有节点内容
String resSucc = "<result><MSG><MSG name=\"测试\"><array><AAC>*****</AAC><AAE>****</AAE><AAA>*</AAA><AAC>*</AAC><AAC>***</AAC><AAC>********</AAC><AAC>******</AAC></array></MSG><SU>****</SU></MSG><SU>****</SU></result>";

// String转XML
Document document = DocumentHelper.parseText(resSucc);
// 获取根节点
Element rootElement = document.getRootElement();
parse(rootElement);

public static void parse(Element root) {
    
    
    List el = root.elements();//获得当前节点的所有子节点
    //遍历每个子节点
    for (Object o : el) {
    
    
        Element element = (Element) o;
        //如果该节点含有文本数据,也就是叶节点
        if (element.isTextOnly()) {
    
    
            List attList = element.attributes();//获得所有属性
            for (Object e : attList) {
    
    
                System.out.println(element.getQName().getName() + "元素的" + ((Attribute) e).getQName().getName() +
                                   "属性值为:" + ((Attribute) e).getValue());
            }
            //输出子节点的文本数据
            System.out.println(element.getTextTrim());
        } else {
    
    
            parse(element);
        }
    }
}
1.8.7 elementIterator()
/**
 * 对Document对象调用getRootElement()方法可以返回代表根节点的Element对象。拥有了一个Element对象后,可以对该对象调用elementIterator()方法获得它的子节点的Element对象们的一个迭代器。使用(Element)iterator.next()方法遍历一个iterator并把每个取出的元素转化为Element类型。
 */
public static Document load(String filename) {
    
      
    Document document = null;  
    try {
    
      
        SAXReader saxReader = new SAXReader();  
        document = saxReader.read(new File(filename)); // 读取XML文件,获得document对象  
    } catch (Exception ex) {
    
      
        ex.printStackTrace();  
    }  
    return document;  
} 

public boolean isOnly(String catNameEn, HttpServletRequest request,  
                      String xml) {
    
      
    boolean flag = true;  
    String path = request.getRealPath("");  
    Document doc = load(path + "/" + xml);  
    Element root = doc.getRootElement();  
    for (Iterator i = root.elementIterator(); i.hasNext();) {
    
      
        Element el = (Element) i.next();  
        if (catNameEn.equals(el.elementTextTrim("engName"))) {
    
      
            flag = false;  
            break;  
        }  
    }  
    return flag;  
} 
1.8.8 Qname()
Qname:
1.来历:qname是qualified name 的简写
2.构成:由名字空间(namespace)前缀(prefix)以及冒号(:),还有一个元素名称构成
3.举例:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
     version="1.0">
  <xsl:template match="foo">
    <hr/>
  </xsl:template>
</xsl:stylesheet>
xsl是名字空间前缀,template是元素名称,xsl:template 就是一个qname
4.总结:qname无非是有着特定格式的xml元素,其作用主要是增加了名字空间,比如有同样的元素名称,而名字空间不同的情况。
    
public static void main(String[] args) throws DocumentException {
    
    
    String text = "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n" +
        "xmlns=\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"\n" +
        "version=\"1.0\">\n" +
        "<xsl:template match=\"foo\">\n" +
        "<hr/>\n" +
        "</xsl:template>\n" +
        "</xsl:stylesheet>";
    Document document = DocumentHelper.parseText(text);
    Element rootElement = document.getRootElement();
    System.out.println("args = [" + rootElement.getQName().getNamespacePrefix() + "]");
    System.out.println("args = [" + rootElement.getQName().getQualifiedName() + "]");
    System.out.println("args = [" + rootElement.getQName("xsl:stylesheet").getName() + "]");
    System.out.println("args = [" + rootElement.getQName().toString() + "]");
    System.out.println("args = [" + rootElement.getQName().getNamespace() + "]");
}

// 打印内容:
// NamespacePrefix = [xsl]
// QualifiedName = [xsl:stylesheet]
// QName = [stylesheet]
// args = [org.dom4j.QName@e42e6155 [name: stylesheet namespace: "org.dom4j.Namespace@ed4197ca [Namespace: prefix xsl mapped to URI "http://www.w3.org/1999/XSL/Transform"]"]]
// Namespace = [org.dom4j.Namespace@ed4197ca [Namespace: prefix xsl mapped to URI "http://www.w3.org/1999/XSL/Transform"]]

猜你喜欢

转载自blog.csdn.net/zhangwenchao0814/article/details/109017838