add XML content custom support

This commit is contained in:
Looly 2021-08-31 10:15:54 +08:00
parent 838a3ecfa4
commit 166d46d137
7 changed files with 417 additions and 318 deletions

View File

@ -3,13 +3,14 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.11 (2021-08-30) # 5.7.11 (2021-08-31)
### 🐣新特性 ### 🐣新特性
* 【crypto 】 修改SymmetricCrypto初始化逻辑 * 【crypto 】 修改SymmetricCrypto初始化逻辑
* 【core 】 FileTypeUtil增加对wps编辑的docx的识别issue#I47JGH@Gitee * 【core 】 FileTypeUtil增加对wps编辑的docx的识别issue#I47JGH@Gitee
* 【core 】 Money修改构造0表示读取所有分issue#1796@Github * 【core 】 Money修改构造0表示读取所有分issue#1796@Github
* 【json 】 增加JSONXMLParser和JSONXMLSerializer
* 【json 】 XML支持自定义内容标签issue#I47TV8@Gitee
### 🐞Bug修复 ### 🐞Bug修复
* 【cron 】 **重要**修复Scheduler启动默认线程池为null的bugissue#I47PZW@Gitee * 【cron 】 **重要**修复Scheduler启动默认线程池为null的bugissue#I47PZW@Gitee

View File

@ -1,6 +1,7 @@
package cn.hutool.json; package cn.hutool.json;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
@ -17,7 +18,7 @@ import java.util.SortedMap;
* *
* @author Looly * @author Looly
*/ */
final class InternalJSONUtil { public final class InternalJSONUtil {
private InternalJSONUtil() { private InternalJSONUtil() {
} }
@ -28,27 +29,30 @@ final class InternalJSONUtil {
* @param obj 被检查的对象 * @param obj 被检查的对象
* @throws JSONException If o is a non-finite number. * @throws JSONException If o is a non-finite number.
*/ */
protected static void testValidity(Object obj) throws JSONException { static void testValidity(Object obj) throws JSONException {
if (false == ObjectUtil.isValidIfNumber(obj)) { if (false == ObjectUtil.isValidIfNumber(obj)) {
throw new JSONException("JSON does not allow non-finite numbers."); throw new JSONException("JSON does not allow non-finite numbers.");
} }
} }
/** /**
* 值转为String用于JSON中 If the object has an value.toJSONString() method, then that method will be used to produce the JSON text. <br> * 值转为String用于JSON中规则为
* The method is required to produce a strictly conforming text. <br> * <ul>
* If the object does not contain a toJSONString method (which is the most common case), then a text will be produced by other means. <br> * <li>对象如果实现了{@link JSONString}接口调用{@link JSONString#toJSONString()}方法</li>
* If the value is an array or Collection, then a JSONArray will be made from it and its toJSONString method will be called. <br> * <li>对象如果实现了{@link JSONString}接口调用{@link JSONString#toJSONString()}方法</li>
* If the value is a MAP, then a JSONObject will be made from it and its toJSONString method will be called. <br> * <li>对象如果是数组或Collection包装为{@link JSONArray}</li>
* Otherwise, the value's toString method will be called, and the result will be quoted.<br> * <li>对象如果是Map包装为{@link JSONObject}</li>
* <li>对象如果是数字使用{@link NumberUtil#toStr(Number)}转换为字符串</li>
* <li>其他情况调用toString并使用双引号包装</li>
* </ul>
* *
* @param value 需要转为字符串的对象 * @param value 需要转为字符串的对象
* @return 字符串 * @return 字符串
* @throws JSONException If the value is or contains an invalid number. * @throws JSONException If the value is or contains an invalid number.
*/ */
protected static String valueToString(Object value) throws JSONException { static String valueToString(Object value) throws JSONException {
if (value == null || value instanceof JSONNull) { if (value == null || value instanceof JSONNull) {
return "null"; return JSONNull.NULL.toString();
} }
if (value instanceof JSONString) { if (value instanceof JSONString) {
try { try {
@ -66,7 +70,7 @@ final class InternalJSONUtil {
} else if (value instanceof Collection) { } else if (value instanceof Collection) {
Collection<?> coll = (Collection<?>) value; Collection<?> coll = (Collection<?>) value;
return new JSONArray(coll).toString(); return new JSONArray(coll).toString();
} else if (value.getClass().isArray()) { } else if (ArrayUtil.isArray(value)) {
return new JSONArray(value).toString(); return new JSONArray(value).toString();
} else { } else {
return JSONUtil.quote(value.toString()); return JSONUtil.quote(value.toString());
@ -79,16 +83,13 @@ final class InternalJSONUtil {
* @param string A String. * @param string A String.
* @return A simple JSON value. * @return A simple JSON value.
*/ */
protected static Object stringToValue(String string) { public static Object stringToValue(String string) {
// null处理 // null处理
if (null == string || "null".equalsIgnoreCase(string)) { if (StrUtil.isEmpty(string) || StrUtil.NULL.equalsIgnoreCase(string)) {
return JSONNull.NULL; return JSONNull.NULL;
} }
// boolean处理 // boolean处理
if (0 == string.length()) {
return StrUtil.EMPTY;
}
if ("true".equalsIgnoreCase(string)) { if ("true".equalsIgnoreCase(string)) {
return Boolean.TRUE; return Boolean.TRUE;
} }
@ -130,7 +131,7 @@ final class InternalJSONUtil {
* @param value * @param value
* @return JSONObject * @return JSONObject
*/ */
protected static JSONObject propertyPut(JSONObject jsonObject, Object key, Object value) { static JSONObject propertyPut(JSONObject jsonObject, Object key, Object value) {
final String[] path = StrUtil.splitToArray(Convert.toStr(key), CharUtil.DOT); final String[] path = StrUtil.splitToArray(Convert.toStr(key), CharUtil.DOT);
int last = path.length - 1; int last = path.length - 1;
JSONObject target = jsonObject; JSONObject target = jsonObject;
@ -160,7 +161,7 @@ final class InternalJSONUtil {
* @return 是否忽略null值 * @return 是否忽略null值
* @since 4.3.1 * @since 4.3.1
*/ */
protected static boolean defaultIgnoreNullValue(Object obj) { static boolean defaultIgnoreNullValue(Object obj) {
return (false == (obj instanceof CharSequence))// return (false == (obj instanceof CharSequence))//
&& (false == (obj instanceof JSONTokener))// && (false == (obj instanceof JSONTokener))//
&& (false == (obj instanceof Map)); && (false == (obj instanceof Map));
@ -178,12 +179,12 @@ final class InternalJSONUtil {
* @return 是否有序 * @return 是否有序
* @since 5.7.0 * @since 5.7.0
*/ */
protected static boolean isOrder(Object value){ static boolean isOrder(Object value) {
if(value instanceof LinkedHashMap || value instanceof SortedMap){ if (value instanceof LinkedHashMap || value instanceof SortedMap) {
return true; return true;
} else if(value instanceof JSONGetter){ } else if (value instanceof JSONGetter) {
final JSONConfig config = ((JSONGetter<?>) value).getConfig(); final JSONConfig config = ((JSONGetter<?>) value).getConfig();
if(null != config){ if (null != config) {
return config.isOrder(); return config.isOrder();
} }
} }

View File

@ -1,16 +1,15 @@
package cn.hutool.json; package cn.hutool.json;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.EscapeUtil; import cn.hutool.json.xml.JSONXMLParser;
import cn.hutool.core.util.StrUtil; import cn.hutool.json.xml.JSONXMLSerializer;
import java.util.Iterator;
/** /**
* 提供静态方法在XML和JSONObject之间转换 * 提供静态方法在XML和JSONObject之间转换
* *
* @author JSON.org * @author JSON.org, looly
* @see JSONXMLParser
* @see JSONXMLSerializer
*/ */
public class XML { public class XML {
@ -92,189 +91,23 @@ public class XML {
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray * 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray
* *
* @param jo JSONObject * @param jo JSONObject
* @param string XML字符串 * @param xmlStr XML字符串
* @param keepStrings If true, then values will not be coerced into boolean or numeric values and will instead be left as strings * @param keepStrings 如果为{@code true}则值保持String类型不转换为数字或boolean
* @return A JSONObject containing the structured data from the XML string. * @return A JSONObject 解析后的JSON对象与传入的jo为同一对象
* @throws JSONException Thrown if there is an errors while parsing the string * @throws JSONException 解析异常
* @since 5.3.1 * @since 5.3.1
*/ */
public static JSONObject toJSONObject(JSONObject jo, String string, boolean keepStrings) throws JSONException { public static JSONObject toJSONObject(JSONObject jo, String xmlStr, boolean keepStrings) throws JSONException {
XMLTokener x = new XMLTokener(string, jo.getConfig()); JSONXMLParser.parseJSONObject(jo, xmlStr, keepStrings);
while (x.more() && x.skipPast("<")) {
parse(x, jo, null, keepStrings);
}
return jo; return jo;
} }
/**
* Scan the content following the named tag, attaching it to the context.
*
* @param x The XMLTokener containing the source string.
* @param context The JSONObject that will include the new material.
* @param name The tag name.
* @return true if the close tag is processed.
* @throws JSONException JSON异常
*/
private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings) throws JSONException {
char c;
int i;
JSONObject jsonobject;
String string;
String tagName;
Object token;
// Test for and skip past these forms:
// <!-- ... -->
// <! ... >
// <![ ... ]]>
// <? ... ?>
// Report errors for these forms:
// <>
// <=
// <<
token = x.nextToken();
// <!
if (token == BANG) {
c = x.next();
if (c == '-') {
if (x.next() == '-') {
x.skipPast("-->");
return false;
}
x.back();
} else if (c == '[') {
token = x.nextToken();
if ("CDATA".equals(token)) {
if (x.next() == '[') {
string = x.nextCDATA();
if (string.length() > 0) {
context.accumulate("content", string);
}
return false;
}
}
throw x.syntaxError("Expected 'CDATA['");
}
i = 1;
do {
token = x.nextMeta();
if (token == null) {
throw x.syntaxError("Missing '>' after '<!'.");
} else if (token == LT) {
i += 1;
} else if (token == GT) {
i -= 1;
}
} while (i > 0);
return false;
} else if (token == QUEST) {
// <?
x.skipPast("?>");
return false;
} else if (token == SLASH) {
// Close tag </
token = x.nextToken();
if (name == null) {
throw x.syntaxError("Mismatched close tag " + token);
}
if (!token.equals(name)) {
throw x.syntaxError("Mismatched " + name + " and " + token);
}
if (x.nextToken() != GT) {
throw x.syntaxError("Misshaped close tag");
}
return true;
} else if (token instanceof Character) {
throw x.syntaxError("Misshaped tag");
// Open tag <
} else {
tagName = (String) token;
token = null;
jsonobject = new JSONObject();
for (; ; ) {
if (token == null) {
token = x.nextToken();
}
// attribute = value
if (token instanceof String) {
string = (String) token;
token = x.nextToken();
if (token == EQ) {
token = x.nextToken();
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
}
jsonobject.accumulate(string, keepStrings ? token : InternalJSONUtil.stringToValue((String) token));
token = null;
} else {
jsonobject.accumulate(string, "");
}
} else if (token == SLASH) {
// Empty tag <.../>
if (x.nextToken() != GT) {
throw x.syntaxError("Misshaped tag");
}
if (jsonobject.size() > 0) {
context.accumulate(tagName, jsonobject);
} else {
context.accumulate(tagName, "");
}
return false;
} else if (token == GT) {
// Content, between <...> and </...>
for (; ; ) {
token = x.nextContent();
if (token == null) {
if (tagName != null) {
throw x.syntaxError("Unclosed tag " + tagName);
}
return false;
} else if (token instanceof String) {
string = (String) token;
if (string.length() > 0) {
jsonobject.accumulate("content", keepStrings ? token : InternalJSONUtil.stringToValue(string));
}
} else if (token == LT) {
// Nested element
if (parse(x, jsonobject, tagName, keepStrings)) {
if (jsonobject.size() == 0) {
context.accumulate(tagName, "");
} else if (jsonobject.size() == 1 && jsonobject.get("content") != null) {
context.accumulate(tagName, jsonobject.get("content"));
} else {
context.accumulate(tagName, jsonobject);
}
return false;
}
}
}
} else {
throw x.syntaxError("Misshaped tag");
}
}
}
}
/** /**
* 转换JSONObject为XML * 转换JSONObject为XML
* Convert a JSONObject into a well-formed, element-normal XML string.
* *
* @param object A JSONObject. * @param object JSON对象或数组
* @return A string. * @return XML字符串
* @throws JSONException Thrown if there is an error parsing the string * @throws JSONException JSON解析异常
*/ */
public static String toXml(Object object) throws JSONException { public static String toXml(Object object) throws JSONException {
return toXml(object, null); return toXml(object, null);
@ -282,122 +115,26 @@ public class XML {
/** /**
* 转换JSONObject为XML * 转换JSONObject为XML
* Convert a JSONObject into a well-formed, element-normal XML string.
* *
* @param object A JSONObject. * @param object JSON对象或数组
* @param tagName The optional name of the enclosing tag. * @param tagName 可选标签名称名称为空时忽略标签
* @return A string. * @return A string.
* @throws JSONException Thrown if there is an error parsing the string * @throws JSONException JSON解析异常
*/ */
public static String toXml(Object object, String tagName) throws JSONException { public static String toXml(Object object, String tagName) throws JSONException {
if (null == object) { return toXml(object, tagName, "content");
return null;
}
StringBuilder sb = new StringBuilder();
JSONArray ja;
JSONObject jo;
String key;
Iterator<String> keys;
Object value;
if (object instanceof JSONObject) {
// Emit <tagName>
if (tagName != null) {
sb.append('<');
sb.append(tagName);
sb.append('>');
}
// Loop thru the keys.
jo = (JSONObject) object;
keys = jo.keySet().iterator();
while (keys.hasNext()) {
key = keys.next();
value = jo.get(key);
if (value == null) {
value = StrUtil.EMPTY;
} else if (ArrayUtil.isArray(value)) {
value = new JSONArray(value);
}
// Emit content in body
if ("content".equals(key)) {
if (value instanceof JSONArray) {
ja = (JSONArray) value;
int i = 0;
for (Object val : ja) {
if (i > 0) {
sb.append('\n');
}
sb.append(EscapeUtil.escapeXml(val.toString()));
i++;
}
} else {
sb.append(EscapeUtil.escapeXml(value.toString()));
}
// Emit an array of similar keys
} else if (value instanceof JSONArray) {
ja = (JSONArray) value;
for (Object val : ja) {
if (val instanceof JSONArray) {
sb.append('<');
sb.append(key);
sb.append('>');
sb.append(toXml(val));
sb.append("</");
sb.append(key);
sb.append('>');
} else {
sb.append(toXml(val, key));
}
}
} else if ("".equals(value)) {
sb.append('<');
sb.append(key);
sb.append("/>");
// Emit a new tag <k>
} else {
sb.append(toXml(value, key));
}
}
if (tagName != null) {
// Emit the </tagname> close tag
sb.append("</");
sb.append(tagName);
sb.append('>');
}
return sb.toString();
}
if (ArrayUtil.isArray(object)) {
object = new JSONArray(object);
}
if (object instanceof JSONArray) {
ja = (JSONArray) object;
for (Object val : ja) {
// XML does not have good support for arrays. If an array
// appears in a place where XML is lacking, synthesize an
// <array> element.
sb.append(toXml(val, tagName == null ? "array" : tagName));
}
return sb.toString();
}
String string = EscapeUtil.escapeXml(object.toString());
return (tagName == null) ?
"\"" + string + "\"" : (string.length() == 0) ? "<" + tagName + "/>"
: "<" + tagName + ">" + string + "</" + tagName + ">";
} }
/**
* 转换JSONObject为XML
*
* @param object JSON对象或数组
* @param tagName 可选标签名称名称为空时忽略标签
* @param contentKeys 标识为内容的key,遇到此key直接解析内容而不增加对应名称标签
* @return A string.
* @throws JSONException JSON解析异常
*/
public static String toXml(Object object, String tagName, String... contentKeys) throws JSONException {
return JSONXMLSerializer.toXml(object, tagName, contentKeys);
}
} }

View File

@ -0,0 +1,182 @@
package cn.hutool.json.xml;
import cn.hutool.json.InternalJSONUtil;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.XML;
import cn.hutool.json.XMLTokener;
/**
* XML解析器将XML解析为JSON对象
*
* @author JSON.org, looly
* @since 5.7.11
*/
public class JSONXMLParser {
/**
* 转换XML为JSONObject
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray
*
* @param jo JSONObject
* @param xmlStr XML字符串
* @param keepStrings 如果为{@code true}则值保持String类型不转换为数字或boolean
* @throws JSONException 解析异常
*/
public static void parseJSONObject(JSONObject jo, String xmlStr, boolean keepStrings) throws JSONException {
XMLTokener x = new XMLTokener(xmlStr, jo.getConfig());
while (x.more() && x.skipPast("<")) {
parse(x, jo, null, keepStrings);
}
}
/**
* Scan the content following the named tag, attaching it to the context.
*
* @param x The XMLTokener containing the source string.
* @param context The JSONObject that will include the new material.
* @param name The tag name.
* @return true if the close tag is processed.
* @throws JSONException JSON异常
*/
private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings) throws JSONException {
char c;
int i;
JSONObject jsonobject;
String string;
String tagName;
Object token;
token = x.nextToken();
if (token == XML.BANG) {
c = x.next();
if (c == '-') {
if (x.next() == '-') {
x.skipPast("-->");
return false;
}
x.back();
} else if (c == '[') {
token = x.nextToken();
if ("CDATA".equals(token)) {
if (x.next() == '[') {
string = x.nextCDATA();
if (string.length() > 0) {
context.accumulate("content", string);
}
return false;
}
}
throw x.syntaxError("Expected 'CDATA['");
}
i = 1;
do {
token = x.nextMeta();
if (token == null) {
throw x.syntaxError("Missing '>' after '<!'.");
} else if (token == XML.LT) {
i += 1;
} else if (token == XML.GT) {
i -= 1;
}
} while (i > 0);
return false;
} else if (token == XML.QUEST) {
// <?
x.skipPast("?>");
return false;
} else if (token == XML.SLASH) {
// Close tag </
token = x.nextToken();
if (name == null) {
throw x.syntaxError("Mismatched close tag " + token);
}
if (!token.equals(name)) {
throw x.syntaxError("Mismatched " + name + " and " + token);
}
if (x.nextToken() != XML.GT) {
throw x.syntaxError("Misshaped close tag");
}
return true;
} else if (token instanceof Character) {
throw x.syntaxError("Misshaped tag");
// Open tag <
} else {
tagName = (String) token;
token = null;
jsonobject = new JSONObject();
for (; ; ) {
if (token == null) {
token = x.nextToken();
}
// attribute = value
if (token instanceof String) {
string = (String) token;
token = x.nextToken();
if (token == XML.EQ) {
token = x.nextToken();
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
}
jsonobject.accumulate(string, keepStrings ? token : InternalJSONUtil.stringToValue((String) token));
token = null;
} else {
jsonobject.accumulate(string, "");
}
} else if (token == XML.SLASH) {
// Empty tag <.../>
if (x.nextToken() != XML.GT) {
throw x.syntaxError("Misshaped tag");
}
if (jsonobject.size() > 0) {
context.accumulate(tagName, jsonobject);
} else {
context.accumulate(tagName, "");
}
return false;
} else if (token == XML.GT) {
// Content, between <...> and </...>
for (; ; ) {
token = x.nextContent();
if (token == null) {
if (tagName != null) {
throw x.syntaxError("Unclosed tag " + tagName);
}
return false;
} else if (token instanceof String) {
string = (String) token;
if (string.length() > 0) {
jsonobject.accumulate("content", keepStrings ? token : InternalJSONUtil.stringToValue(string));
}
} else if (token == XML.LT) {
// Nested element
if (parse(x, jsonobject, tagName, keepStrings)) {
if (jsonobject.size() == 0) {
context.accumulate(tagName, "");
} else if (jsonobject.size() == 1 && jsonobject.get("content") != null) {
context.accumulate(tagName, jsonobject.get("content"));
} else {
context.accumulate(tagName, jsonobject);
}
return false;
}
}
}
} else {
throw x.syntaxError("Misshaped tag");
}
}
}
}
}

View File

@ -0,0 +1,159 @@
package cn.hutool.json.xml;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.EscapeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
/**
* JSON转XML字符串工具
*
* @author looly
* @since 5.7.11
*/
public class JSONXMLSerializer {
/**
* 转换JSONObject为XML
* Convert a JSONObject into a well-formed, element-normal XML string.
*
* @param object A JSONObject.
* @return A string.
* @throws JSONException Thrown if there is an error parsing the string
*/
public static String toXml(Object object) throws JSONException {
return toXml(object, null);
}
/**
* 转换JSONObject为XML
*
* @param object JSON对象或数组
* @param tagName 可选标签名称名称为空时忽略标签
* @return A string.
* @throws JSONException JSON解析异常
*/
public static String toXml(Object object, String tagName) throws JSONException {
return toXml(object, tagName, "content");
}
/**
* 转换JSONObject为XML
*
* @param object JSON对象或数组
* @param tagName 可选标签名称名称为空时忽略标签
* @param contentKeys 标识为内容的key,遇到此key直接解析内容而不增加对应名称标签
* @return A string.
* @throws JSONException JSON解析异常
*/
public static String toXml(Object object, String tagName, String... contentKeys) throws JSONException {
if (null == object) {
return null;
}
final StringBuilder sb = new StringBuilder();
if (object instanceof JSONObject) {
// Emit <tagName>
appendTag(sb, tagName, false);
// Loop thru the keys.
((JSONObject) object).forEach((key, value) -> {
if (ArrayUtil.isArray(value)) {
value = new JSONArray(value);
}
// Emit content in body
if (ArrayUtil.contains(contentKeys, key)) {
if (value instanceof JSONArray) {
int i = 0;
for (Object val : (JSONArray) value) {
if (i > 0) {
sb.append(CharUtil.LF);
}
sb.append(EscapeUtil.escapeXml(val.toString()));
i++;
}
} else {
sb.append(EscapeUtil.escapeXml(value.toString()));
}
// Emit an array of similar keys
} else if (StrUtil.isEmptyIfStr(value)) {
sb.append(wrapWithTag(null, key));
} else if (value instanceof JSONArray) {
for (Object val : (JSONArray) value) {
if (val instanceof JSONArray) {
sb.append(wrapWithTag(toXml(val), key));
} else {
sb.append(toXml(val, key));
}
}
} else {
sb.append(toXml(value, key));
}
});
// Emit the </tagname> close tag
appendTag(sb, tagName, true);
return sb.toString();
}
if (ArrayUtil.isArray(object)) {
object = new JSONArray(object);
}
if (object instanceof JSONArray) {
for (Object val : (JSONArray) object) {
// XML does not have good support for arrays. If an array
// appears in a place where XML is lacking, synthesize an
// <array> element.
sb.append(toXml(val, tagName == null ? "array" : tagName));
}
return sb.toString();
}
return wrapWithTag(EscapeUtil.escapeXml(object.toString()), tagName);
}
/**
* 追加标签
*
* @param sb XML内容
* @param tagName 标签名
* @param isEndTag 是否结束标签
* @since 5.7.11
*/
private static void appendTag(StringBuilder sb, String tagName, boolean isEndTag) {
if (StrUtil.isNotBlank(tagName)) {
sb.append('<');
if (isEndTag) {
sb.append('/');
}
sb.append(tagName).append('>');
}
}
/**
* 将内容使用标签包装为XML
*
* @param tagName 标签名
* @param content 内容
* @return 包装后的XML
* @since 5.7.11
*/
private static String wrapWithTag(String content, String tagName) {
if (StrUtil.isBlank(tagName)) {
return StrUtil.wrap(content, "\"");
}
if (StrUtil.isEmpty(content)) {
return "<" + tagName + "/>";
} else {
return "<" + tagName + ">" + content + "</" + tagName + ">";
}
}
}

View File

@ -0,0 +1,6 @@
/**
* JSON与XML相互转换封装基于json.org官方库改造
*
* @author looly
*/
package cn.hutool.json.xml;

View File

@ -1,5 +1,8 @@
package cn.hutool.json; package cn.hutool.json.xml;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.json.XML;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -25,4 +28,14 @@ public class XMLTest {
Assert.assertEquals(xml, xml2); Assert.assertEquals(xml, xml2);
} }
@Test
public void xmlContentTest(){
JSONObject jsonObject = JSONUtil.createObj().set("content","123456");
String xml = XML.toXml(jsonObject);
Assert.assertEquals("123456", xml);
xml = XML.toXml(jsonObject, null, new String[0]);
Assert.assertEquals("<content>123456</content>", xml);
}
} }