JAVA语言设计一个简单的XML文档生成器

最近做了一个公司的笔试题,使用Java语言设计一个简单xml文档生成器,自己尝试写了一遍。

题目

1、设计一个简单的XML文档生成器,它满足以下功能:

1)节点能够添加或者删除其它子节点, 操作同时要保证每个节点只能有一个父节点, 一个节点只能从属于一个父节点;

2) 节点能够获取父节点对象;节点能够获取所有子节点对象。

3)节点有添加或者读取XML属性的操作;

4)当前节点有方法能打印当前节点和所有子节点(包括子孙节点)的内容。

5)XML的encoding方式能够设置,如:

xml在线生成javabean xml在线生成器_java


要求:

1)用java写出完整程序;

2)主程序测试生成器,它构建下面文档,然后打印出来。

xml在线生成javabean xml在线生成器_java_02

代码实现

1、先创建一个循环队列,后面层次遍历树结构使用。

/**
 * 循环队列
 */
public class MyQueue {
    /**
     * 初始化大小
     */
    private final int SIZE = 20;

    /**
     * 数据
     */
    private Object[] queArray;

    /**
     * 队头
     */
    private int front;

    /**
     * 队尾
     */
    private int rear;

    public MyQueue(){
        queArray = new Object[SIZE];
        front = 0;
        rear = -1;
    }

    /**
     * 入队
     * @param o
     */
    public void insert(Object o){
        if (rear == SIZE - 1){
            rear = -1;
        }
        queArray[++rear] = o;
    }

    /**
     * 出队
     * @return
     */
    public Object remove(){
        Object temp = queArray[front++];
        if (front == SIZE){
            front = 0;
        }
        return temp;
    }

    /**
     * 判空
     * @return
     */
    public boolean isEmpty(){
        return (rear + 1 == front || front + SIZE - 1 == rear);
    }
}

2、创建节点类。

package com.zsc.xml;

import lombok.*;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * xml节点
 */
@Setter
@Getter
@Accessors(chain = true)
public class Node {
    /**
     * 节点名称
     */
    private String name;

    /**
     * 节点Id
     */
    private String id;

    /**
     * 节点描述
     */
    private String description;

    /**
     * 子节点
     */
    private List<Node> childNodes = new ArrayList<>();

    /**
     * 父节点
     */
    private Node parentNode;


    /**
     * 添加子节点
     * @param childNode
     */
    public void setChildNode(Node childNode){
        if (childNode.getParentNode() == null){
            throw new RuntimeException("加入的子节点不存在父节点,设置失败!");
        }
        List<Node> nodes = childNode.getParentNode().getChildNodes();
        if (!nodes.isEmpty()){
            Optional<Node> optional = nodes.stream().filter(n -> n.getName().equals(childNode.getName())).findFirst();
            if (optional.isPresent()){
                throw new RuntimeException("父节点" + childNode.getParentNode().getName() + "已存在" + optional.get().getName() +"节点了,添加失败!");
            }
        }
        nodes.add(childNode);
        childNode.getParentNode().setChildNodes(nodes);
    }

    /**
     * 查找到顶端节点
     * @return
     */
    public Node findParentNode(){
        Node parentTemp = parentNode == null ? this : parentNode;
        while (parentTemp.getParentNode() != null){
            parentTemp = parentTemp.getParentNode();
        }
        return parentTemp;
    }

    /**
     * 层次遍历xml树结构
     * 如果传入的参数不为null,则遍历当前节点有方法能打印当前节点和所有子节点(包括子孙节点)的内容
     * @param n
     */
    public void printNodeInfo(Node n){
        Node root = null;
        if (n != null){
            root = n;
        }else {
            //获取顶端root节点
            root = findParentNode();
        }
        MyQueue queue = new MyQueue();
        //根节点先被访问,入队
        queue.insert(root);
        while (!queue.isEmpty()){
            Node temp = (Node) queue.remove();
            System.out.println(temp.getName() + "--------->" +(temp.getParentNode() == null? "不存在父节点":"父节点为:" + temp.getParentNode().getName()));
            List<Node> nodes = temp.getChildNodes();
            if (!nodes.isEmpty()){
                for (Node node : nodes) {
                    //入队
                    queue.insert(node);
                }
            }
        }
    }

    /**
     * 递归删除关联节点
     * @param node
     */
    public static void removeNode(Node node){
        //该节点的子节点
        List<Node> nodes = node.getChildNodes();
        if (!nodes.isEmpty()){
            List<Node> tempNodes = new ArrayList<>(nodes);
            for (Node n : tempNodes) {
                removeNode(n);
            }
        }
        //移除对应的父节点里面的子节点
        Node parentNode = node.getParentNode();
        if (parentNode != null){
            List<Node> childNodes = parentNode.getChildNodes();
            childNodes.remove(node);
            node.getParentNode().setChildNodes(childNodes);
        }
        node.setParentNode(null);
    }

    /**
     * 递归构建xml文件格式
     * @return
     */
   public static String createXml(Node node){
        StringBuilder builder = new StringBuilder();
        if (!StringUtils.isEmpty(node.getName())){
            builder.append("<").append(node.getName());
            if (!StringUtils.isEmpty(node.getId())){
                builder.append(" ID=\"").append(node.getId()).append("\"");
            }
            builder.append(">").append("\r\n");
            if (!StringUtils.isEmpty(node.getDescription())){
                builder.append(node.getDescription()).append("\r\n");
            }
            //获取该节点的子节点
            List<Node> childNodes = node.getChildNodes();
            if (!childNodes.isEmpty()){
                for (Node childNode : childNodes) {
                    //递归调用
                    builder.append(createXml(childNode));
                }
            }
            builder.append("</").append(node.getName()).append(">").append("\r\n");
        }
        return builder.toString();

   }


}

3、创建XmlBuilder类。

package com.zsc.xml;


import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;

/**
 * XML生成
 */
@Setter
@Getter
public class XMLBuilder {
    /**
     * 版本
     */
    private String version;

    /**
     * 编码
     */
    private String encoding;

    /**
     * 生成头文件
     * @param version
     * @param encoding
     * @return
     */
    public String createXmlHeader(String version,String encoding){
        if (StringUtils.isEmpty(version)) return "";
        if (StringUtils.isEmpty(encoding)) return "";
        this.version = version;
        this.encoding = encoding;
        StringBuilder builder = new StringBuilder();
        builder.append("<?xml version=\"").append(this.version).append("\"")
                .append(" encoding=\"").append(this.encoding).append("\"?>")
                .append("\r\n");
        return builder.toString();
    }


    /**
     * 打印xml结构
     * @param node
     */
    public void printXmlInfo(String version,String encoding,Node node){
        String xml = this.createXmlHeader(version, encoding) + Node.createXml(node);
        System.out.println(xml);
    }

    public static void main(String[] args) {
        Node root = new Node();
        root.setId("").setName("CategoryList").setDescription("");

        Node node1 = new Node();
        node1.setParentNode(root).setName("Category").setId("01").setDescription("");
        root.setChildNode(node1);

        Node node2 = new Node();
        node2.setParentNode(node1).setName("MainCategory").setId("").setDescription("XML");
        node1.setChildNode(node2);

        Node node3 = new Node();
        node3.setParentNode(node1).setName("Description").setId("").setDescription("This is a list my XML articles.");
        node1.setChildNode(node3);

        Node node4 = new Node();
        node4.setParentNode(node1).setName("Active").setId("").setDescription("true");
        node1.setChildNode(node4);

//        Node node5 = new Node();
//        node5.setParentNode(node4).setId("01").setName("test").setDescription("test");
//        node4.setChildNode(node5);

//        Node.removeNode(node1);
//
//        root.printNodeInfo(null);

//        System.out.println(Node.createXml(root));

        XMLBuilder xmlBuilder = new XMLBuilder();
        xmlBuilder.printXmlInfo("1.0","UTF-8",root);

        System.out.println("-----------------------------删除MainCategory节点后------------------------------------------------------");
        Node.removeNode(node2);
        xmlBuilder.printXmlInfo("1.0","UTF-8",root);

        System.out.println("-----------------------------删除Category节点后------------------------------------------------------");
        Node.removeNode(node1);
        xmlBuilder.printXmlInfo("1.0","UTF-8",root);
    }
}