使用注解实现XML构建与解析
基于 dom4j
实现XML构建与解析
# 导入依赖
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
<!-- XPATH 支持-->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
# 测试代码
点击查看
@Getter
@Setter
@ToString
@SIP("Control")
@Accessors(chain = true)
public class Control extends XMLMessage {
public Control() {
}
@SIP("SN")
private String sn;
@SIP("DeviceID")
private String deviceId;
@SIP("PTZCmd")
private String ptzCmd;
@SIP("Info")
private List<Control.Info> info;
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public static class Info extends ChildNode {
@SIP("ControlPriority")
private String controlPriority;
}
@Override
public String toXML() {
return SimpleXmlHelper.toXml(this);
}
}
private static XMLMessage getControl() {
Control message = new Control();
message.setSn("11");
message.setDeviceId("64010000041310000345");
message.setPtzCmd("A50F4D1000001021");
List<Control.Info> list = Arrays.asList(
new Control.Info().setControlPriority("1"),
new Control.Info().setControlPriority("2")
);
message.setInfo(list);
return message;
}
private static <T extends XMLMessage> T convert(XMLMessage message, Class<T> cla) {
String xml = SimpleXmlHelper.toXml(message);
System.out.println(xml);
return SimpleXmlHelper.xlmToBeam(xml, cla);
}
public static void main(String[] args) {
Control message = convert(getControl(), Control.class);
System.out.println(message);
}
# 具体实现
展开详情
# 建立相关注解
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface XML {
String value();
boolean isChild() default false;
}
@Repeatable(SIPAttrs.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface XMLAttr {
String value();
String field();
}
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface XMLAttrs {
XMLAttr [] value();
}
@Getter
public abstract class XMLMessage {
public abstract String toXML();
}
子节点标识
public abstract class ChildNode {
}
@Getter
@Slf4j
@SuppressWarnings("unused")
public class SimpleXmlHelper {
private final Document document;
private final Element rootElement;
private SimpleXmlHelper(String rootName){
this.document = createDocument();
this.rootElement = document.addElement(rootName);
}
/**
* 构建一个 SimpleXmlHelper
* @param rootName 根节点名字
* @return SimpleXmlHelper
*/
public static SimpleXmlHelper build(String rootName){
return new SimpleXmlHelper(rootName);
}
/**
* 将对象转换为XML
* @param obg 转换数据
* @return XML STR
*/
public static <T extends XMLMessage> String toXml(T obg){
SimpleXmlHelper simpleXmlHelper = build(getRootElementNameByClass(obg.getClass()));
simpleXmlHelper.fullElement(simpleXmlHelper.getRootElement(), obg);
return simpleXmlHelper.writeXml();
}
/**
* XLM To Bean
* @param xml xml
* @param cla 需要构建的数据类型
* @param <T> 数据泛型
*/
public static <T extends XMLMessage> T xlmToBeam(String xml,Class<T> cla){
Element rootElement = SimpleXmlHelper.getRoot(xml);
return elementToBean(rootElement,cla);
}
/**
* 填充完整Element
* @param current 当前 Element
* @param t 填充数据
* @param <T> 填充数据泛型
*/
@SuppressWarnings("unchecked")
private <T> void fullElement(Element current, T t){
for (Field field : ReflectUtil.getFields(t.getClass())) {
String name = getNodeNameByField(field);
if(null == name){
log.warn("当前跳过属性[{}],如果需要此属性请添加@SIP注解",field.getName());
continue;
}
Class<?> type = field.getType();
//得到当前字段值
Object fieldValue = ReflectUtil.getFieldValue(t, field);
//得到字段所注解的属性
List<Attribute> attrs = getAttrs(field, t);
if(Collection.class.isAssignableFrom(type) ){
List<Object> valList = (List<Object>) fieldValue;
if(CollUtil.isEmpty(valList)){
continue;
}
for (Object val : valList) {
genElementByFieldName(current, val, name,attrs);
}
}else {
genElementByFieldName(current, fieldValue, name,attrs);
}
}
}
/**
* 构建一个名字为 tagName 并携带 attrs 属性的节点
* @param current 当前 Element
* @param val 当前属性值
* @param tagName 当前xml tag名字
* @param attrs 节点属性
*/
private void genElementByFieldName(Element current, Object val, String tagName,List<Attribute> attrs) {
if(val instanceof ChildNode){
Element child = current.addElement(tagName);
child.setAttributes(attrs);
fullElement(child, val);
}else {
Element child;
if(null == val){
child = createNullNextElement(current, tagName);
}else {
child = createNextElement(current, tagName, val);
}
child.setAttributes(attrs);
}
}
/**
* Element To Bean
* @param currentNode 当前XML节点
* @param cla 需要构建的数据类型
* @param <T> 数据泛型
*/
@SuppressWarnings("unchecked")
public static <T> T elementToBean(Node currentNode,Class<T> cla){
try {
T obg = cla.newInstance();
//得到根节点名字
for (Field field : ReflectUtil.getFields(obg.getClass())) {
String name = getNodeNameByField(field);
if(null == name){
continue;
}
Class<?> type = field.getType();
if(Collection.class.isAssignableFrom(type) ){
List<Node> nodes = findNodes(currentNode, genAllXpath(name));
if(CollUtil.isEmpty(nodes)){
continue;
}
ArrayList<Object> listVal = new ArrayList<>();
for (Node node : nodes) {
//转换为list泛型
Type actualTypeArgument = getActualTypeArgument(field);
T item = elementToBean(node, (Class<T>) actualTypeArgument);
listVal.add(item);
}
ReflectUtil.setFieldValue(obg,field,listVal);
}else {
Node nextNode = findNode(currentNode, name);
//判断 type 是不是 ChildNode的子类
if(ChildNode.class.isAssignableFrom(type)){
if(null == nextNode){
continue;
}
Object childOng = elementToBean(nextNode, type);
ReflectUtil.setFieldValue(obg,field,childOng);
}else {
//设置对象值
ReflectUtil.setFieldValue(obg,field, getNodeVal(nextNode));
}
}
}
return obg;
} catch (Exception e) {
log.error(" ogb to xml 失败");
throw new RuntimeException(e);
}
}
private static <T> void setObgAttrs(Node node, T obg) {
List<Attribute> elementAttrs = getElementAttrs((DefaultElement)node);
for (Attribute attribute : elementAttrs) {
String attrName = attribute.getName();
String attrVal= attribute.getValue();
Field attrField = ReflectUtil.getField(obg.getClass(), attrName);
if(null !=attrField){
ReflectUtil.setFieldValue(obg,attrField,attrVal);
}
}
}
/**
* 得到field 注解属性
* @param field field
* @param obg 当前对象
* @return List<Attribute>
*/
private static <T> List<Attribute> getAttrs(Field field, T obg) {
SIPAttr[] attrs = getSipAttrs(field);
Map<String, String> attrMap = new HashMap<>();
List<Attribute> attributes = new ArrayList<>();
if(0 < attrs.length){
for (SIPAttr attr : attrs) {
String join = attr.field();
Object attrVal = ReflectUtil.getFieldValue(obg, join);
if(null == attrVal){
continue;
}
attributes.add(
new DefaultAttribute(attr.value(),String.valueOf(attrVal))
);
}
}
return attributes;
}
/**
* 得到 SIPAttr 注解
* @param field 当前字段
* @return SIPAttr[]
*/
private static SIPAttr[] getSipAttrs(Field field) {
return field.getDeclaredAnnotationsByType(SIPAttr.class);
}
public static Type getActualTypeArgument(Field field){
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
// 获取泛型类型的实际类型参数
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
return actualTypeArguments[0];
} else {
log.error("请为:{}属性指定泛型",field.getName());
throw new RuntimeException(String.format("请为:%s属性指定泛型",field.getName()));
}
}
/**
* 得到XML 根节点类型
* @param xml xml
* @return 根节点名字
*/
public static String getXlmRootNodeName(String xml){
return getNodeName(SimpleXmlHelper.getRoot(xml));
}
/**
* 得到根节点名字 (class中 {@link SIP} 的值)
* @param cls class
* @return 根节点名字
* @param <T> T
*/
public static <T> String getRootElementNameByClass(Class<T> cls){
SIP cla = cls.getAnnotation(SIP.class);
if(cla == null){
log.warn("请给{}添加@SIP注解",cls.getName());
throw new RuntimeException(String.format("请给%s添加@SIP注解",cls.getName()));
}
return cla.value();
}
/**
* 得到根节点名字 (class中 {@link SIP} 的值)
* @param field class
* @return 根节点名字
*/
public static String getNodeNameByField(Field field){
SIP annotation = field.getAnnotation(SIP.class);
if(null == annotation){
return null;
}
return annotation.value();
}
/**
* 创建 根Element 的下级Element
* @param key Element name
* @return 下级Element
*/
public Element createRootNextElement(String key) {
return createRootNextElement(key,null);
}
/**
* 创建 根Element 的下级Element,并设置值
* @param key Element name
* @return 下级Element
*/
public Element createRootNextElement(String key,Map<String,String> nodes) {
return createNextElement(rootElement,key,nodes);
}
/**
* 创建 指定Element 的下级Element
* @param key Element name
* @return 下级Element
*/
public Element createNextElement(Element element, String key) {
return element.addElement(key);
}
/**
* 创建 指定Element 的下级Element,并设置值
* @param key Element name
* @param nodes nodes 节点值key val形式
* @return 下级Element
*/
public Element createNextElement(Element element, String key, Map<String,String> nodes) {
Element current = createNextElement(element,key);
if(null == nodes){
return current;
}
nodes.forEach((k,v)-> current.addElement(k).setText(v));
return current;
}
/**
* 创建 指定Element 的下级Element,并设置空值
* @param key Element name
* @param val val 节点值
* @return 下级Element
*/
@SuppressWarnings("all")
public Element createNullNextElement(Element element, String key) {
return createNextElement(element,key, Arrays.asList(""));
}
/**
* 创建 指定Element 的下级Element,并设置值
* @param key Element name
* @param val val 节点值
* @return 下级Element
*/
@SuppressWarnings("all")
public Element createNextElement(Element element, String key, Object ...val) {
return createNextElement(element,key, Arrays.asList(val));
}
/**
* 创建 指定Element 的下级Element,并设置值
* @param key Element name
* @param val val 节点值
* @return 下级Element
*/
public Element createNextElement(Element element, String key, List<Object> val) {
Element current = createNextElement(element,key);
val.stream().map(String::valueOf).forEach(current::addText);
return current;
}
/**
* 根节点下添加 k,v
* @param key key
* @param val val
*/
public void appendRoot(String key,String val) {
setElementNodeVal(rootElement,key,val);
}
/**
* 指定 current 下添加 k,v
* @param current 当前current
* @param key key
* @param val val
*/
public void setElementNodeVal(Element current, String key, String val) {
// Element element = current.addElement(key);
Element element = createNextElement(current,key);
if(null!=val && !val.isEmpty()){
element.setText(val);
}
}
/**
* 写出 XML
* @return XML
*/
public String writeXml() {
try{
StringWriter content = new StringWriter();
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(content, format);
writer.write(document);
writer.close();
return content.toString();
} catch (IOException e) {
throw new RuntimeException("生成XML错误");
}
}
/**
* 得到 List<Element> 需要判空
* @param element Element
* @param name name
* @return 获取到的 List<Element>
*/
public static List<Element> findElements(Element element, String name) {
return element.elements(name);
}
/**
* 得到 Element Attrs
* @param element Element
* @return 获取到的 Element
*/
public static List<Attribute> getElementAttrs(DefaultElement element) {
return element.attributes();
}
/**
* 得到 Element 需要判空
* @param element Element
* @param name name
* @return 获取到的 Element
*/
public static Element findElement(Element element, String name) {
return element.element(name);
}
/**
* 得到 Element
* @param element Element
* @param name name
* @return Element 内容
*/
public static String findElementVal(Element element, String name) {
Element elm = element.element(name);
if(null == elm){
return null;
}
return elm.getText();
}
public static String genAllXpath(String xpath) {
return "//"+xpath;
}
/**
* 得到 Nodes 需要判空
* @param node node
* @param xpath xpath
* @return 获取到的 List<Node>
*/
public static List<Node> findNodes(Node node, String xpath) {
XPath userXPath = node.createXPath(xpath);
return userXPath.selectNodes(node);
}
/**
* 得到 Node 需要判空
* @param node 当前 node
* @param xpath xpath
* @return 获取到的 Node
*/
public static Node findNode(Node node, String xpath) {
XPath userXPath = node.createXPath(xpath);
return userXPath.selectSingleNode(node);
}
/**
* 得到 Node 需要判空
* @param node 当前Node
* @param xpath xpath
* @return Node内容
*/
public static String findNodeVal(Node node, String xpath) {
XPath userXPath = node.createXPath(xpath);
Node selectNode = userXPath.selectSingleNode(node);
if(null == selectNode){
return null;
}
return selectNode.getText();
}
/**
* 得到 Node 名字
* */
public static String getNodeName(Node node) {
return node.getName();
}
/**
* 得到 Node 值
* */
public static String getNodeVal(Node node) {
if(null == node){
return "";
}
return node.getText();
}
/**
* 读取XML
* @param xml xml内容
* @return Document
*/
public static Document read(String xml) {
try {
SAXReader reader = new SAXReader();
return reader.read(new StringReader(xml));
} catch (Exception e) {
throw new RuntimeException("读取XML失败");
}
}
/**
* 得到根节点
* @param document document
* @return Element
*/
public static Element getRoot(Document document) {
try {
return document.getRootElement();
} catch (Exception e) {
throw new RuntimeException("读取XML失败");
}
}
/**
* 得到根节点
* @param xml xml内容
* @return Element
*/
public static Element getRoot(String xml) {
try {
return read(xml).getRootElement();
} catch (Exception e) {
throw new RuntimeException("读取XML失败");
}
}
}
上次更新: 2024/11/05, 08:29:31