XML和JSON【转】

以下内容转载和参考自:廖雪峰的官方网站

1、XML

①、DOM方式解析XML

使用DOM是一次性读取XML,并在内存中表示为树形结构,其解析出来的树会增加一个根节点Document:

import java.io.IOException;
import java.io.InputStream;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

public class Main {
    public static void main(String[] args){
        InputStream input = Main.class.getResourceAsStream("book.xml");
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try{
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(input); //parse()可以接收InputStream,File或者URL
            printNode(doc,0);

        }catch (ParserConfigurationException ex) {
            //newDocumentBuilder() error
            System.out.println(ex.getMessage());
        }catch (IOException | SAXException | IllegalArgumentException ex){
            //parse() error: IO错误、解析错误、参数为NULL
            System.out.println(ex.getMessage());
        }
    }

    public static void printNode(Node n, int indent) {
        for (int i = 0; i < indent; i++) {
            System.out.print("  ");
        }
        switch (n.getNodeType()) {
            case Node.DOCUMENT_NODE: // Document根节点
                System.out.println("Document: " + n.getNodeName());
                break;
            case Node.ELEMENT_NODE: // 元素节点
                System.out.println("Element: " + n.getNodeName());
                break;
            case Node.TEXT_NODE: // 文本
                System.out.println("Text: " + n.getNodeName() + " = " + n.getNodeValue());
                break;
            case Node.ATTRIBUTE_NODE: // 属性
                System.out.println("Attr: " + n.getNodeName() + " = " + n.getNodeValue());
                break;
            default: // 其他
                System.out.println("NodeType: " + n.getNodeType() + ", NodeName: " + n.getNodeName());
        }
        for (Node child = n.getFirstChild(); child != null; child = child.getNextSibling()) {
            printNode(child, indent + 1);
        }
    }
}

  ②、使用SAX解析XML

    SAX是一种基于流的解析方式,边读取XML边解析,并以事件回调的方式让调用者获取数据。因为是一边读一边解析,所以无论XML有多大,占用的内存都很小。

SAX解析会触发以下的一系列事件,所以我们需要给SAX传入一个继承自DefaultHandler的回调对象,具体使用SAX的相关可以参考廖雪峰的官方网站 。

  • startDocument:开始读取XML文档;
  • startElement:读取到了一个元素,例如<book>
  • characters:读取到了字符;
  • endElement:读取到了一个结束的元素,例如</book>
  • endDocument:读取XML文档结束。

  ③、使用Jackson

    如下所示的XML的结构,它完全可以对应到一个定义好的JavaBean中,使用开源库Jackson可以轻松做到XML到JavaBean的转换。使用Jackson将XML转换到JavaBean中的详见廖雪峰的官方网站。

<?xml version="1.0" encoding="UTF-8" ?>
<book id="1">
    <name>Java核心技术</name>
    <author>Cay S. Horstmann</author>
    <tags>
        <tag>Java</tag>
        <tag>Network</tag>
    </tags>
</book>
public class Book {
	public long id;
	public String name;
	public String author;
	public List<String> tags;
}

2、JSON

   

  JSON中大括号及其内容称为对象(object),其包含一个或多个元素,元素又称属性,每个元素用逗号分隔。
  元素是键值对类型的,元素的“键”必须为字符串,元素的“值”可以为数字、字符串、逻辑值(true/false)、null,也可以为对象或对象数组。 

  JSON规范中不支持注释,使用json-schema或JSON5的话支持。

下面是使用Jackson来进行JSON和JavaBean的相互转换的示例:

public class TestJackson {
  public static void main(String[] args) throws IOException {
   
    Map<String,Object> params = new HashMap<>();
    params.put("name","jack");
    params.put("age",18);
   
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES/*如果JavaBean不存在该属性时解析不会报错*/, false); //反序列化(JSON 2 JavaBean)时忽略在 json 中存在但 Java 对象不存在的属性
    ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); //在序列化(JavaBean 2 JSON)时忽略值为 null 的属性
    
  
    //将对象转为JSON串
    String jsonString = objectMapper.writeValueAsString(params);
    System.out.println(jsonString);

     
    //将JSON串 转为 Object 对象
    Map resultMap = objectMapper.readValue(jsonString, HashMap.class);
    resultMap.entrySet().stream().forEach(entry ->{
      System.out.println(entry);
    });
  }
}
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

class Book{
    public float num;
    public boolean  flag;
    public HashMap name;
    public List<String> tags;
    public List<HashMap> names;
}

public class Main {
    public static void main(String[] argc) throws Exception{
        InputStream input = Main.class.getResourceAsStream("book.json");
        ObjectMapper mapper = new ObjectMapper();
       
        Book book = mapper.readValue(input, Book.class); //反序列化:JSON 2 JavaBean
        String json = mapper.writeValueAsString(book); //序列化:JavaBean 2 JSON
        json = mapper.writeValueAsString(List.of(book)); //序列化:支持将JavaBean的集合转换为JSON
    }
}

   在序列化的时候,如果JavaBean中的成员没有被初始化或者设置值的话,会将该属性的值序列化为null。对于List会当做一个元素(key为List名,value为数组),对于map成员也会当做一个元素(key为map的名称,value为一个对象,对象中的元素为map中的成员):

  要把JSON的某些值解析为指定的类型的话,需要提供一个转换方法,如将"978-7-111-54742-6"转换为BigInteger类型: 

  Jackson会将枚举类型序列化为String类型:

  其它注意事项:

  在反序列化时,Jackson要求Java类需要一个默认的无参数构造方法,否则,无法直接实例化此类。所以对于存在带参数构造方法的类,如果要反序列化,注意要再提供一个无参数构造方法。

  对于record类型(java 14),Jackson会自动找出它的带参数构造方法,并根据JSON的key进行匹配,可直接反序列化。对record类型的支持需要版本2.12.0以上。 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值