All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.xml.XmlUtil Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.feilong.xml;

import static com.feilong.core.Validator.isNullOrEmpty;
import static com.feilong.core.lang.StringUtil.EMPTY;
import static com.feilong.core.util.MapUtil.newLinkedHashMap;
import static com.feilong.formatter.FormatterUtil.formatToSimpleTable;
import static java.util.Collections.emptyMap;

import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathConstants;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.feilong.core.Validate;
import com.feilong.json.JsonUtil;
import com.feilong.lib.lang3.StringUtils;
import com.feilong.lib.xstream.XStream;
import com.feilong.xml.xstream.XStreamConfig;
import com.feilong.xml.xstream.XStreamConfigBuilder;
import com.feilong.xml.xstream.converters.SimpleMapConverter;

/**
 * xml 工具.
 * 
 * 

* Convenience methods for working with the DOM API, in particular for working with DOM Nodes and DOM Elements. *

* * 将object转成xml字符串. * *

使用示例:

* *
*

* 对于将下面的对象,转成XML
* User user = new User(1L); *

*

* 1.不带XStreamConfig参数
* 使用 {@code com.feilong.xml.XmlUtil.toXML(user, null)},则返回 * *

 * {@code
 *  
 *   feilong
 *   1
 *   
 *   
 * 
 * }
 * 
* *

* * *

* * 2.设置 Alias 参数
* 可以看到上面的结果中,XML Root元素名字是 com.feilong.test.User,如果只是显示成 {@code }怎么做呢?
* 使用 * * *

 *     User user = new User(1L);
 *     XStreamConfig xStreamConfig = new XStreamConfig();
 *     xStreamConfig.getAliasMap().put("user", User.class);
 *     LOGGER.info(XmlUtil.toXML(user, xStreamConfig));
 * 
* * * ,则返回 * *
 * {@code
 * 
 *   feilong
 *   1
 *   
 *   
 * 
 * }
 * 
* *

*

* * 3.设置 ImplicitCollection 参数
* 如果我在结果不想出现 {@code }怎么做呢?
* 使用 * * *

 *     User user = new User(1L);
 *     XStreamConfig xStreamConfig = new XStreamConfig();
 *     xStreamConfig.getAliasMap().put("user", User.class);
 *     xStreamConfig.getImplicitCollectionMap().put("userAddresseList", User.class);
 *     LOGGER.info(XmlUtil.toXML(user, xStreamConfig));
 * 
* * * ,则返回 * *
 * {@code
 *  
 *   feilong
 *   1
 *   
 * 
 * }
 * 
* *

*
* * @author feilong * @author feilong * @author feilong * @see Frequently Asked Questions * @see News * @see "org.apache.solr.common.util.DOMUtil" * @see "org.springframework.util.xml.DomUtils" * @since 3.0.0 */ public class XmlUtil{ /** The Constant LOGGER. */ private static final Logger LOGGER = LoggerFactory.getLogger(XmlUtil.class); /** Don't let anyone instantiate this class. */ private XmlUtil(){ //AssertionError不是必须的. 但它可以避免不小心在类的内部调用构造器. 保证该类在任何情况下都不会被实例化. //see 《Effective Java》 2nd throw new AssertionError("No " + getClass().getName() + " instances for you!"); } //--------------------------------------------------------------- /** * 根据xpath表达式, 来获得节点的名字和string value map. * *

* 按照顺序返回 *

* * @param xml * the xml * @param xpathExpression * the xpath expression * @return 如果 xml 是null,抛出 {@link NullPointerException}
* @since 3.0.0 */ public static Map getNodeNameAndStringValueMap(Object xml,String xpathExpression){ return getNodeMap( xml, xpathExpression, // (map,node) -> map.put(node.getNodeName(), node.getTextContent())); } /** * 获得 node attribute value and string value map. * * @param xml * the xml * @param xpathExpression * the xpath expression * @param nodeAttributeName * the node attribute name * @return 如果 xml 是null,抛出 {@link NullPointerException}
* @since 3.0.0 */ public static Map getNodeAttributeValueAndStringValueMap( Object xml, String xpathExpression, final String nodeAttributeName){ return getNodeMap( xml, xpathExpression, // (map,node) -> map.put(getAttributeValue(node, nodeAttributeName), node.getTextContent())); } /** * Gets the node map. * * @param xml * the xml * @param xpathExpression * the xpath expression * @param hook * the hook * @return 如果 xml 是null,抛出 {@link NullPointerException}
*/ private static Map getNodeMap(Object xml,String xpathExpression,Hook hook){ Document document = FeilongDocumentBuilder.buildDocument(xml); NodeList nodeList = XPathUtil.evaluate(document, xpathExpression, XPathConstants.NODESET); if (null == nodeList || 0 == nodeList.getLength()){ if (LOGGER.isInfoEnabled()){ LOGGER.info("use xpathExpression:[{}],from xml:[{}], can not find Node,return emptyMap", xpathExpression, format(document)); } return emptyMap(); } //--------------------------------------------------------------- Map map = newLinkedHashMap(); for (int i = 0, j = nodeList.getLength(); i < j; ++i){ Node node = nodeList.item(i); if (Node.ELEMENT_NODE == node.getNodeType()){ hook.hook(map, node); } } //--------------------------------------------------------------- if (LOGGER.isTraceEnabled()){ LOGGER.trace("nameAndValueMap:{}", formatToSimpleTable(map)); } return map; } //--------------------------------------------------------------- /** * 获得node属性值. * * @param node * 节点 * @param attributeName * 属性名称 * @return 获得node属性值
* 如果 attributeName 是null,抛出 {@link NullPointerException}
* 如果 attributeName 是blank,抛出 {@link IllegalArgumentException}
*/ private static String getAttributeValue(Node node,String attributeName){ Validate.notNull(node, "node can't be null!"); Validate.notBlank(attributeName, "attributeName can't be null/empty!"); //--------------------------------------------------------------- NamedNodeMap namedNodeMap = node.getAttributes(); Node currentNode = namedNodeMap.getNamedItem(attributeName); if (null != currentNode){ return currentNode.getNodeValue(); } return EMPTY; } //--------------------------------------------------------------- /** * Format. * * @param xml * the xml * @return the string * @since 3.0.0 */ public static String format(String xml){ Node node = FeilongDocumentBuilder.buildDocument(xml); return format(node); } /** * Format. * * @param node * the node * @return the string * @throws UncheckedXmlParseException * the unchecked xml parse exception * @since 3.0.0 */ private static String format(Node node){ try{ Writer writer = new StringWriter(); StreamResult streamResult = new StreamResult(writer); TransformerBuilder.DEFAULT_TRANSFORMER.transform(// new DOMSource(node), streamResult); return writer.toString(); }catch (TransformerException e){ throw new UncheckedXmlParseException(e); } } //--------------------------------------------------------------- /** * 将 map 转成 xml string. * *

示例:

* *
* *
     * Map{@code } map = new HashMap{@code <>}();
     * map.put("out_trade_no", "112122212");
     * map.put("total_fee", "125.00");
     * map.put("call_back_url", "");
     * map.put("notify_url", "");
     * 
     * LOGGER.debug(XmlUtil.toXML(map, "xml"));
     * 
* * 返回: * *
     * {@code 
     *     
     *       
     *       125.00
     *       
     *       112122212
     *     
     * }
     * 
* *
* * @param * the key type * @param * the value type * @param map * the map * @param rootElementName * 根元素名字 * @return 如果 rootName 是null,抛出 {@link NullPointerException}
* 如果 rootName 是blank,抛出 {@link IllegalArgumentException}
* 如果 map 是null,抛出 {@link NullPointerException}
* 如果 map 是empty,抛出 {@link IllegalArgumentException}
* 如果 map 有 null key,将抛出 异常
* 如果 map 有 null value,将转成 {@link StringUtils#EMPTY}代替
* * @see SimpleMapConverter * @since 1.10.7 */ public static String toXML(Map map,String rootElementName){ return toXML(map, rootElementName, true); } /** * 将 map 转成 xml 字符串. * *

示例:

* *
* *
     * Map{@code } map = new HashMap{@code <>}();
     * map.put("out_trade_no", "112122212");
     * map.put("total_fee", "125.00");
     * map.put("call_back_url", "");
     * map.put("notify_url", "");
     * 
     * LOGGER.debug(XmlUtil.toXML(map, "xml",true));
     * 
* * 返回: * *
     * {@code 
     *     
     *       
     *       125.00
     *       
     *       112122212
     *     
     * }
     * 
* * 如果此时,使用 isPrettyPrintfalse 参数 * *
     * Map{@code } map = new HashMap{@code <>}();
     * map.put("out_trade_no", "112122212");
     * map.put("total_fee", "125.00");
     * map.put("call_back_url", "");
     * map.put("notify_url", "");
     * 
     * LOGGER.debug(XmlUtil.toXML(map, "xml",false));
     * 
* * 返回: * *
     * {@code 
    125.00112122212
     * }
     * 
* *
* * @param * the key type * @param * the value type * @param map * the map * @param rootElementName * 根元素名字 * @param isPrettyPrint * 是否格式化输出 * @return 如果 rootName 是null,抛出 {@link NullPointerException}
* 如果 rootName 是blank,抛出 {@link IllegalArgumentException}
* 如果 map 是null,抛出 {@link NullPointerException}
* 如果 map 是empty,抛出 {@link IllegalArgumentException}
* 如果 map 有 null key,将抛出 异常
* 如果 map 有 null value,将转成 {@link StringUtils#EMPTY}代替
* @see SimpleMapConverter */ public static String toXML(Map map,String rootElementName,boolean isPrettyPrint){ Validate.notEmpty(map, "map can't be null/empty!"); Validate.notBlank(rootElementName, "rootName can't be blank!"); XStreamConfig xStreamConfig = XStreamConfigBuilder.buildSimpleMapXStreamConfig(rootElementName, isPrettyPrint); // xStreamConfig.getDefaultImplementationMap().put(map.getClass(), Map.class) if (map.getClass() != HashMap.class){ xStreamConfig.getAliasMap().put(rootElementName, map.getClass()); } return toXML(map, xStreamConfig); } /** * 将object转成xml字符串. * *

使用示例:

* *
* *

* 对于将下面的对象,转成XML
* User user = new User(1L); *

* *

* 1.不带XStreamConfig参数
* 使用 {@code com.feilong.xml.XmlUtil#toXML(user, null)},则返回 * *

     * {@code
     *  
     *   feilong
     *   1
     *   
     *   
     * 
     * }
     * 
* *

* * *

* * 2.设置 Alias 参数
* 可以看到上面的结果中,XML Root元素名字是 com.feilong.test.User,如果只是显示成 {@code }怎么做呢?
* 使用 * * *

     *     User user = new User(1L);
     *     XStreamConfig xStreamConfig = new XStreamConfig();
     *     xStreamConfig.getAliasMap().put("user", User.class);
     *     LOGGER.info(XmlUtil.toXML(user, xStreamConfig));
     * 
* * * ,则返回 * *
     * {@code
     * 
     *   feilong
     *   1
     *   
     *   
     * 
     * }
     * 
* *

*

* * 3.设置 ImplicitCollection 参数
* 如果我在结果不想出现 {@code }怎么做呢?
* 使用 * * *

     *     User user = new User(1L);
     *     XStreamConfig xStreamConfig = new XStreamConfig();
     *     xStreamConfig.getAliasMap().put("user", User.class);
     *     xStreamConfig.getImplicitCollectionMap().put("userAddresseList", User.class);
     *     LOGGER.info(XmlUtil.toXML(user, xStreamConfig));
     * 
* * * ,则返回 * *
     * {@code
     *  
     *   feilong
     *   1
     *   
     * 
     * }
     * 
* *

*
* * @param bean * the obj * @param xStreamConfig * the to xml config * @return 如果 bean 是null,抛出 {@link NullPointerException}
* @see com.feilong.lib.xstream.XStream#toXML(Object) * @see com.feilong.lib.xstream.XStream#alias(String, Class) * @see com.feilong.lib.xstream.XStream#addImplicitCollection(Class, String) */ public static String toXML(Object bean,XStreamConfig xStreamConfig){ Validate.notNull(bean, "bean can't be null!"); if (LOGGER.isDebugEnabled()){ String pattern = "class:[{}],bean:[{}],xStreamConfig:[{}]"; LOGGER.debug(pattern, bean.getClass().getSimpleName(), JsonUtil.format(bean), JsonUtil.format(xStreamConfig)); } return XStreamUtil.toXML(bean, xStreamConfig); } //--------------------------------------------------------------- /** * 将{@code xml}字符串转成 Map. * *

注意:

*
*
    *
  1. 内部封装了 {@link XStream#ignoreUnknownElements()} 忽略了不存在的字段
  2. *
*
*

示例:

* *
* *
     * String xml = "{@code \r\n" + "\r\n"
     *                 + "\r\n" + "\r\n"
     *                 + "\r\n" + "\r\n"
     *                 + "\r\n" + "\r\n"
     *                 + "}";
     * 
     * Map{@code } map = XmlUtil.fromXML(xml, "xml");
     * LOGGER.debug(JsonUtil.format(map));
     * 
* * 返回: * *
    {
            "result_code": "SUCCESS",
            "sign": "288AE0E455273102147B9CF95F43D222",
            "mch_id": "1239453402",
            "sub_mch_id": "",
            "return_msg": "OK",
            "appid": "wx2cc3b3d8bb8df520",
            "nonce_str": "I1dy6p9hOy324Q2M",
            "return_code": "SUCCESS"
        }
     * 
* *
* * @param xml * the xml * @param rootElementName * the root element name * @return 如果 rootElementName 是null,抛出 {@link NullPointerException}
* 如果 rootElementName 是blank,抛出 {@link IllegalArgumentException}
* 如果 xml 是null,返回 null
* @since 3.0.0 change name from fromXMl */ public static Map toMap(String xml,String rootElementName){ Validate.notBlank(rootElementName, "rootElementName can't be blank!"); if (isNullOrEmpty(xml)){ return null; } return toBean(xml, XStreamConfigBuilder.buildSimpleMapXStreamConfig(rootElementName)); } /** * 将 xml 字符串,转成带注解的 processAnnotationsType 对象. * *

注意:

*
*
    *
  1. 内部封装了 {@link XStream#ignoreUnknownElements()} 忽略了不存在的字段
  2. *
*
* *

示例:

* *
* * 已知从微信得到下列xml * *
     * {@code 
     
         
         
         
         
         
         
         
         
     
     }
     * 
* * 需要转换成下列的 WechatCloseResponse 对象 * *
    
    {@code @XStreamAlias("xml")}
    public class WechatCloseResponse{
    
        //** 返回状态码 return_code 是 String(16) SUCCESS SUCCESS/FAIL. 
        {@code @XStreamAlias("return_code")}
        private String return_code;
    
        //** 返回信息 return_msg 否 String(128).
        {@code @XStreamAlias("return_msg")}
        private String return_msg;
    
        //** 公众账号ID appid 是 String(32) wx8888888888888888 微信分配的公众账号ID. 
        {@code @XStreamAlias("appid")}
        private String appid;
    
       //** 商户号 mch_id 是 String(32) 1900000109 微信支付分配的商户号. 
        {@code @XStreamAlias("mch_id")}
        private String mch_id;
    
        //** 随机字符串 nonce_str 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法.
        {@code @XStreamAlias("nonce_str")}
        private String nonce_str;
    
        //** 签名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 签名,验证签名算.
        //@XStreamAsAttribute
        {@code @XStreamAlias("sign")}
        private String sign;
    
        //** 业务结果 result_code 是 String(16) SUCCESS SUCCESS/FAIL. 
        {@code @XStreamAlias("result_code")}
        private String result_code;
    
        //** 业务结果描述 result_msg 是 String(32) OK 对于业务执行的详细描述. 
        {@code @XStreamAlias("result_msg")}
        private String result_msg;
    
        //** 错误代码 err_code 否 String(32) SYSTEMERROR 详细参见第6节错误列表.
        {@code @XStreamAlias("err_code")}
        private String err_code;
    
        //** 错误代码描述 err_code_des 否 String(128) 系统错误 结果信息描述. 
        {@code @XStreamAlias("err_code_des")}
        private String err_code_des;
        
        // setter/getter 省略
        
    }
     * 
* * 你可以 * *
     * String xml = {@code "\r\n" + "\r\n"
     *                     + "\r\n" + "\r\n"
     *                     + "\r\n" + "\r\n"
     *                     + "\r\n"
     *                     + "\r\n" + "";}
     * 
     * WechatCloseResponse map = XmlUtil.fromXML(xml, WechatCloseResponse.class);
     * LOGGER.debug("{}", JsonUtil.format(map));
     * 
* * 返回: * *
     * {
     * "sign": "288AE0E455273102147B9CF95F43D222",
     * "result_code": "SUCCESS",
     * "mch_id": "1239453402",
     * "err_code": "",
     * "result_msg": "",
     * "return_msg": "OK",
     * "err_code_des": "",
     * "appid": "wx2cc3b3d8bb8df520",
     * "return_code": "SUCCESS",
     * "nonce_str": "I1dy6p9hOy324Q2M"
     * }
     * 
* *
* * @param * the generic type * @param xml * the xml * @param processAnnotationsType * the process annotations type * @return 如果 xml 是null,返回 null
* 如果 processAnnotationsType 是null,抛出 {@link NullPointerException}
* @since 3.0.0 change name from fromXMl */ public static T toBean(String xml,Class processAnnotationsType){ Validate.notNull(processAnnotationsType, "processAnnotationsType can't be blank!"); if (isNullOrEmpty(xml)){ return null; } return toBean(xml, new XStreamConfig(processAnnotationsType)); } /** * From xml. * *

注意:

*
*
    *
  1. 内部封装了 {@link XStream#ignoreUnknownElements()} 忽略了不存在的字段
  2. *
*
* * @param * the generic type * @param xml * the xml * @param xStreamConfig * the x stream config * @return 如果 xml 是null或者是empty,返回 null
* @since 3.0.0 change name from fromXMl */ public static T toBean(String xml,XStreamConfig xStreamConfig){ if (LOGGER.isDebugEnabled()){ LOGGER.debug("input params info,xml:[{}],xStreamConfig:[{}]", xml, JsonUtil.format(xStreamConfig)); } //--------------------------------------------------------------- if (isNullOrEmpty(xml)){ return null; } return XStreamUtil.toBean(xml, xStreamConfig); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy