package thyyxxk.webserver.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.ValueFilter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.*;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * <p>
 * 描述：
 * </p>
 *
 * @author xc
 * @date 2022-03-28 16:28
 */
@Slf4j
public class JsonXmlUtils {
    /**
     * 解决 CDATA 问题
     */
    private static final Pattern PATTERN = Pattern.compile("[<>&\"',]");
    public static ValueFilter filter = (obj, s, v) -> {
        if (v == null) {
            return "";
        }
        return v;
    };

    private static String escape(String string) {
        return PATTERN.matcher(string).find() ? "<![CDATA[" + string + "]]>" : string;
    }

    public static boolean isEmpty(String str) {
        return str == null || str.trim().isEmpty() || "null".equals(str);
    }

    /**
     * updateXml 处理xml头，以及根标签
     */
    private static String updateXml(String xmlStr) {
        xmlStr = xmlStr.trim();
        if (StringUtils.isBlank(xmlStr)) {
            return xmlStr;
        }

        // 过滤非法字符
        xmlStr = xmlStr.replaceAll("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "");

        StringBuilder xmlSb = new StringBuilder(xmlStr);
        if (!xmlStr.startsWith("<?")) {
            xmlSb.insert(0, "<?xml version=\"1.0\" encoding=\"utf-8\"?>");
        }

        int idx = xmlSb.indexOf("?>") + 2;
        xmlSb.insert(idx, "<root_chinadaas>").append("</root_chinadaas>");
        return xmlSb.toString();
    }

    /**
     * xml转json的核心循环方法
     *
     * @param element
     * @param json
     */
    private static void dom4j2Json(Element element, JSONObject json) {
        // 如果是属性
        for (Object o : element.attributes()) {
            Attribute attr = (Attribute) o;
            if (!isEmpty(attr.getValue())) {
                json.put("@" + attr.getName(), attr.getValue());
            }
        }
        List<Element> chdEl = element.elements();
        if (chdEl.isEmpty() && !isEmpty(element.getText())) { // 如果没有子元素,只有一个值
            json.put(element.getName(), element.getText());
        }

        for (Element e : chdEl) { // 有子元素
            if (!e.elements().isEmpty() || e.attributes().size() > 0) { // 子元素也有子元素,
                JSONObject chdjson = new JSONObject();
                dom4j2Json(e, chdjson);
                Object o = json.get(e.getName());
                if (o != null) {
                    JSONArray jsona = null;
                    if (o instanceof JSONObject) { // 如果此元素已存在,则转为jsonArray
                        JSONObject jsono = (JSONObject) o;
                        json.remove(e.getName());
                        jsona = new JSONArray();
                        jsona.add(jsono);
                        jsona.add(chdjson);
                    }
                    if (o instanceof JSONArray) {
                        jsona = (JSONArray) o;
                        jsona.add(chdjson);
                    }
                    json.put(e.getName(), jsona);
                } else {
                    if (!chdjson.isEmpty()) {
                        json.put(e.getName(), chdjson);
                    }
                }
            } else { // 子元素没有子元素
                for (Object o : element.attributes()) {
                    Attribute attr = (Attribute) o;
                    if (!isEmpty(attr.getValue())) {
                        json.put("@" + attr.getName(), attr.getValue());
                    }
                }
                if (!e.getText().isEmpty()) {
                    json.put(e.getName(), e.getText());
                }
            }
        }
    }

    /**
     * xml转Json调用
     *
     * @throws DocumentException
     */
    public static JSONObject xml2Json(String xmlStr) throws DocumentException {
        xmlStr = updateXml(xmlStr);
        Document doc = DocumentHelper.parseText(xmlStr);
        JSONObject json = new JSONObject();
        dom4j2Json(doc.getRootElement(), json);
        return json;
    }

    /**
     * 根据at号获取所有的属性list
     */
    public static JSONObject getAttribute(JSONObject jdata) {
        JSONObject rdata = new JSONObject();
        try {
            Set<Map.Entry<String, Object>> setdata = jdata.entrySet();
            for (Map.Entry<String, Object> en : setdata) {
                if (en.getKey().startsWith("@")) {
                    rdata.put(en.getKey().substring(1), escape((String) en.getValue()));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rdata;
    }

    /**
     * Json to xmlstr 核心循环方法
     */
    public static String json2Xmlstr(JSONObject jObj, StringBuffer buffer) {
        Set<Map.Entry<String, Object>> se = jObj.entrySet();
        for (Map.Entry<String, Object> en : se) {
            switch (en.getValue().getClass().getName()) {
                case "com.alibaba.fastjson.JSONObject":
                    JSONObject jo = jObj.getJSONObject(en.getKey());
                    buffer.append("<").append(en.getKey());

                    //处理xml标签的属性值
                    JSONObject attrlist1 = getAttribute(jo);
                    Set<Map.Entry<String, Object>> attr1 = attrlist1.entrySet();
                    for (Map.Entry<String, Object> amap : attr1) {
                        buffer.append(" ").append(amap.getKey()).append("=\"").append(escape((String) amap.getValue())).append("\"");
                    }
                    buffer.append(">");
                    if (jo.containsKey(en.getKey())) {
                        //标签直接有值的话，直接赋值
                        buffer.append(jo.getString(en.getKey()));
                    } else {
                        json2Xmlstr(jo, buffer);
                    }
                    buffer.append("</").append(en.getKey()).append(">");
                    break;
                case "com.alibaba.fastjson.JSONArray":
                    JSONArray jarray = jObj.getJSONArray(en.getKey());
                    for (int i = 0; i < jarray.size(); i++) {
                        buffer.append("<").append(en.getKey());
                        JSONObject jsonobject = jarray.getJSONObject(i);

                        //处理xml标签的属性值
                        JSONObject attrlist2 = getAttribute(jsonobject);
                        Set<Map.Entry<String, Object>> attr2 = attrlist2.entrySet();
                        for (Map.Entry<String, Object> amap : attr2) {
                            buffer.append(" ").append(amap.getKey()).append("=\"").append(escape((String) amap.getValue())).append("\"");
                        }
                        buffer.append(">");

                        json2Xmlstr(jsonobject, buffer);
                        buffer.append("</").append(en.getKey()).append(">");
                    }
                    break;
                case "java.lang.String":
                    if (!en.getKey().startsWith("@")) {//@号的是属性，在前面已经处理过，这里就不处理了
                        buffer.append("<").append(en.getKey()).append(">").append(escape((String) en.getValue()));
                        buffer.append("</").append(en.getKey()).append(">");
                    }
                    break;
            }
        }
        return buffer.toString();
    }

    /**
     * json转xml调用
     *
     * @param json
     * @return java.lang.String
     */
    public static String json2Xml(String json) {
        try {
            StringBuffer buffer = new StringBuffer();
            JSONObject jObj = JSON.parseObject(json);
            json2Xmlstr(jObj, buffer);
            return buffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

}
