复杂xml解析(JAXB)

本文介绍了Java中JAXB用于复杂XML解析的使用方法,包括@XmlElement、@XmlAttribute等注解的详细解释,并给出了示例代码,展示了如何通过JAXB将XML转换为对象以及对象转为XML。
摘要由CSDN通过智能技术生成

一. 背景

近期因为结束无人机航线规划, 大量结束kml文件(近似xml的文件), 需要解析复杂xml, 了解到一些xml的解析工具,

  1. 学习关键点:
  • 解析
  • 编写
  • 约束文件(DTD文件[.dtd], Schema文件[.xsd]), 即常用的命名空间
  • 验证xml是否符合约束文件
  1. 常见解析工具
  • JDOM(不常用): 底层也是JAXP
  • DOM4J: java比较流行的框架所选
  • JAXB: 特点使用注解, 使用简单
  • JAXP: 原生, 按标签解析或通过SAX进行解析, SAX与easy excel差不多都是按行解析, 如果不做修改, 这种方法占用内存较少

DOM4J需要单独引入依赖, 其他三种, 作者目前使用jdk8完全可以使用(根据不同版本会有不同)

  1. xml的验证
  • DOM4J
  • JAXP

二. 使用

目前遇到的都是复杂xml, 主要使用JAXB解析文件, 其他几种都需要写代码, 匹配标签进行实体类的封装

1. 注解使用

参考博客:JAXB常用注解讲解(超详细)

@XmlRootElement

  • 作用和用法:
    类级别的注解,将类映射为根元素
  • 属性:
    该注解含有name和namespace两个属性。
    • namespace属性用于指定生成的元素所属的命名空间。
    • name属性用于指定生成元素的名字,若不指定则默认使用类名小写作为元素名。

注: 如果类型中使用多个命名空间, 建议所有@XmlRootElement、@Xmllement注解表明命名空间

@XmlElement

  • 作用和用法:
    字段,方法,参数级别的注解。该注解可以将被注解的字段(非静态),或者被注解的get/set方法对应的字段映射为本地元素,也就是子元素。
    默认使用字段名或get/set方法去掉前缀剩下部分小写作为元素名(在字段名和get/set方法符合命名规范的情况下)。

  • 属性:
    该注解的属性常用的属性有有:name、nillable、required、namespace、defaultValue

    • name属性可以指定生成元素的名字,同@XmlRootElement注解的name属性一样,不再举例。
    • namespace属性用于指定生成的元素所属的命名空间。
    • nillable属性可以指定元素的文本值是否可以为空,默认为false。

@XmlAttribute

  • 作用和用法:
    字段和方法级别的注解。该注解会将字段或get/set方法对应的字段映射成本类对应元素的属性,属性名默认使用字段名或get/set方法去掉前缀剩下部分首字母小写(在字段名和get/set方法符合命名规范的情况下)。
  • 属性:
    该注解有name,required,namespace三个属性。用法和@XmlElement注解相同,不再举例。

@XmlTransient

  • 作用和用法:
    类,字段,方法级别的注解。可使JAXB在映射xml元素时忽略被注解的类,字段,get/set对应字段。需要注意的是该注解与所有其他JAXB注释相互排斥,也就是说与其他注释连用就会报错。修改上面例子:

@XmlAccessorType

  • 作用和用法:
    包和类级别的注解。javaEE的API对该注解的解释是:控制字段是否被默认序列化。通俗来讲,就是决定哪些字段或哪些get/set方法对应的字段会被映射为xml元素,需要注意的是字段或get/set方法的访问权限(public/private)会影响字段是否被映射为xml元素,下面会详细讲解。

注: 主要与@XmlElement位置有关

关键属性:

  • XmlAccessType.PROPERTY: 默认, 一般@XmlElement标注在类中getter或setter方法上
  • XmlAccessType.FIELD: 一般@XmlElement标注在类属性上

@XmlSeeAlso

  • 作用和用法
    类注解, 用在父类中, 表明其下所有子类

@XmlType

  • 作用和用法
    类注解, 用于表明一个类的引用, 以及类下属性的解析顺序, 一般用于继承类的识别
    -属性
    name: 引用名称
    propOrder: 属性组

@XmlElementRef

  • 作用和用法
    属性或方法注解, 用与表明引用的类, 主要与@XmlType配合使用, name一致, 一般用于继承类的引用
    -属性
    name: @XmlType的name
    namespace: 命名空间

2. 示例

2.1 基本类

Template类
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TemplateType", propOrder = {
  "document"
})
@XmlRootElement(name = "template", namespace = "http://www.abc.cn")
public class Template implements Cloneable {
  @XmlElementRef(name = "Document", namespace = "http://www.abc.cn")
  protected BaseDocumentType document;
}
BaseDocument类
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BaseDocumentType", propOrder = {
  "author",
  "createTime",
  "updateTime",
})
@XmlSeeAlso({
  TemplateDocument.class,
  WaylineDocument.class
})
@XmlRootElement(name = "Document", namespace = "http://www.abc.cn")
public abstract class BaseDocument {
  @XmlElement(name = "author", namespace = "http://www.abc.cn")
  protected String author;

  @XmlElement(name = "createTime", namespace = "http://www.abc.cn")
  protected Long createTime;

  @XmlElement(name = "updateTime", namespace = "http://www.abc.cn")
  protected Long updateTime;
}
TemplateDocument类
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TemplateDocumentType", propOrder = {
  "folder"
})
@XmlRootElement(name = "Document", namespace = "http://www.abc.cn")
public abstract class TemplateDocument extends BaseDocument {
  @XmlElement(name = "Folder", namespace = "http://www.def.cn")
  protected String folder;
}
WaylineDocument类
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TemplateDocumentType", propOrder = {
  "folder"
})
@XmlRootElement(name = "Document", namespace = "http://www.abc.cn")
public abstract class WaylineDocument extends BaseDocument {
  @XmlElement(name = "Wayline", namespace = "http://www.def.cn")
  protected String Wayline;
}

@XmlElementRef(name = “Document”, namespace = “http://www.abc.cn”)
protected BaseDocumentType document;
这段代码, 会根据@XmlSeeAlso标识的类, 根据标签不同自动匹配

2.2工具类

@Slf4j
public class KMLUtil {
  /** xml 转 对象 */
  public static Template parse(Class<?> clazz, InputStream inputStream) throws JAXBException {
    log.debug("[param:parse]==>clazz:{}, inputStream:{}", clazz, inputStream);
    JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    return (WayLine)unmarshaller.unmarshal(inputStream);
  }

  /** 对象 转 xml */
  public static void format(Template template, String path) throws JAXBException, IOException {
    log.debug("[param:parse]==>wayline:{}, path:{}", template, path);
    JAXBContext jaxbContext = JAXBContext.newInstance(template.getClass());
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    // 禁用默认的XML声明
    marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);

    File file = new File(path);
    if (!file.getParentFile().exists()) {
      file.getParentFile().mkdirs();
    }
    if (!file.exists()) {
      file.createNewFile();
    } else {
      file.delete();
      file.createNewFile();
    }

    StringWriter sw = new StringWriter();
    sw.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    marshaller.marshal(wayline, sw);
    FileWriter fw = new FileWriter(path);
    fw.write(sw.toString());
    fw.flush();
    fw.close();
  }

}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
XML文件比较复杂时,使用JAXB可能会变得不太方便,这时你可以使用DOM或SAX等更高级的XML解析库。下面是一个使用DOM解析复杂XML文件的示例: 1. 在pom.xml中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency> ``` 2. 创建一个控制器类,使用DOM解析XML数据: ``` @RestController @RequestMapping("/api") public class XmlController { @PostMapping("/xml") public String parseXml(@RequestBody String xmlString) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(new StringReader(xmlString)); Document document = db.parse(is); NodeList nodeList = document.getElementsByTagName("person"); StringBuilder sb = new StringBuilder(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) node; String name = element.getElementsByTagName("name").item(0).getTextContent(); int age = Integer.parseInt(element.getElementsByTagName("age").item(0).getTextContent()); sb.append("Name: ").append(name).append(", Age: ").append(age).append("\n"); } } return sb.toString(); } } ``` 在上面的示例中,我们使用了DocumentBuilderFactory和DocumentBuilder来创建一个XML文档的DOM表示。然后,我们使用getNodeList方法获取所有的person元素,并逐个解析它们的子元素。 3. 使用Postman或其他HTTP客户端进行测试: 发送POST请求到http://localhost:8080/api/xml,将以下XML数据作为请求体: ``` <?xml version="1.0" encoding="UTF-8"?> <people> <person> <name>John Doe</name> <age>30</age> </person> <person> <name>Jane Smith</name> <age>25</age> </person> </people> ``` 如果一切正常,你应该会得到以下响应: ``` Name: John Doe, Age: 30 Name: Jane Smith, Age: 25 ``` 这就是使用Spring Boot解析复杂XML文件的一个示例。注意,你可以使用其他XML解析库,例如SAX,来处理更大的XML文件。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值