This commit is contained in:
Looly 2024-04-11 23:27:56 +08:00
parent a066afd4d4
commit 26dcf5fd3d
5 changed files with 99 additions and 25 deletions

View File

@ -195,12 +195,13 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
/**
* 根据lambda的方法引用获取
*
* @param func 方法引用
* @param <P> 参数类型
* @param <T> 返回值类型
* @param <P> 参数类型
* @param <T> 返回值类型
* @return 获取表达式对应属性和返回的对象
*/
public <P, T> T get(final SerFunction<P, T> func){
public <P, T> T get(final SerFunction<P, T> func) {
final LambdaInfo lambdaInfo = LambdaUtil.resolve(func);
return get(lambdaInfo.getFieldName(), lambdaInfo.getReturnType());
}
@ -314,6 +315,38 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @throws JSONException 如果给定键为{@code null}或者键对应的值存在且为非JSONArray
*/
public JSONObject append(final String key, final Object value) throws JSONException {
return append(key, value, null);
}
/**
* 追加值.
* <ul>
* <li>如果键值对不存在或对应值为{@code null}则value为单独值</li>
* <li>如果值是一个{@link JSONArray}追加之</li>
* <li>如果值是一个其他值则和旧值共同组合为一个{@link JSONArray}</li>
* </ul>
*
* @param key
* @param value
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
* @return this.
* @throws JSONException 如果给定键为{@code null}或者键对应的值存在且为非JSONArray
* @since 6.0.0
*/
public JSONObject append(String key, Object value, final Predicate<MutableEntry<String, Object>> predicate) throws JSONException {
// 添加前置过滤通过MutablePair实现过滤修改键值对等
if (null != predicate) {
final MutableEntry<String, Object> pair = new MutableEntry<>(key, value);
if (predicate.test(pair)) {
// 使用修改后的键值对
key = pair.getKey();
value = pair.getValue();
} else {
// 键值对被过滤
return this;
}
}
final Object object = this.getObj(key);
if (object == null) {
this.set(key, value);
@ -396,7 +429,7 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
@Override
public Writer write(final Writer writer, final int indentFactor, final int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException {
final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config)
.beginObj();
.beginObj();
this.forEach((key, value) -> jsonWriter.writeField(new MutableEntry<>(key, value), predicate));
jsonWriter.end();
// 此处不关闭Writer考虑writer后续还需要填内容

View File

@ -20,15 +20,10 @@ import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.reflect.method.MethodUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.json.InternalJSONUtil;
import org.dromara.hutool.json.JSONArray;
import org.dromara.hutool.json.JSONException;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.JSONParser;
import org.dromara.hutool.json.JSONTokener;
import org.dromara.hutool.json.xml.JSONXMLUtil;
import org.dromara.hutool.json.*;
import org.dromara.hutool.json.serialize.GlobalSerializeMapping;
import org.dromara.hutool.json.serialize.JSONSerializer;
import org.dromara.hutool.json.xml.JSONXMLParser;
import org.dromara.hutool.json.xml.ParseConfig;
import java.io.InputStream;
@ -171,7 +166,8 @@ public class JSONObjectMapper {
final String jsonStr = StrUtil.trim(source);
if (StrUtil.startWith(jsonStr, '<')) {
// 可能为XML
JSONXMLUtil.toJSONObject(jsonStr, jsonObject, ParseConfig.of());
//JSONXMLUtil.toJSONObject(jsonStr, jsonObject, ParseConfig.of());
JSONXMLParser.of(ParseConfig.of(), this.predicate).parseJSONObject(jsonStr, jsonObject);
return;
}
mapFromTokener(new JSONTokener(StrUtil.trim(source), jsonObject.config()), jsonObject);

View File

@ -12,6 +12,7 @@
package org.dromara.hutool.json.xml;
import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.xml.XmlConstants;
@ -19,6 +20,8 @@ import org.dromara.hutool.json.JSONException;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.mapper.JSONValueMapper;
import java.util.function.Predicate;
/**
* XML解析器将XML解析为JSON对象
*
@ -27,19 +30,43 @@ import org.dromara.hutool.json.mapper.JSONValueMapper;
*/
public class JSONXMLParser {
/**
* 创建XML解析器
*
* @param parseConfig 解析选项
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
* @return JSONXMLParser
*/
public static JSONXMLParser of(final ParseConfig parseConfig, final Predicate<MutableEntry<String, Object>> predicate) {
return new JSONXMLParser(parseConfig, predicate);
}
private final ParseConfig parseConfig;
private final Predicate<MutableEntry<String, Object>> predicate;
/**
* 构造
*
* @param parseConfig 解析选项
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
*/
public JSONXMLParser(final ParseConfig parseConfig, final Predicate<MutableEntry<String, Object>> predicate) {
this.parseConfig = parseConfig;
this.predicate = predicate;
}
/**
* 转换XML为JSONObject
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray
*
* @param xmlStr XML字符串
* @param jo JSONObject
* @param parseConfig 解析选项
* @throws JSONException 解析异常
*/
public static void parseJSONObject(final String xmlStr, final JSONObject jo, final ParseConfig parseConfig) throws JSONException {
public void parseJSONObject(final String xmlStr, final JSONObject jo) throws JSONException {
final XMLTokener x = new XMLTokener(xmlStr, jo.config());
while (x.more() && x.skipPast("<")) {
parse(x, jo, null, parseConfig, 0);
parse(x, jo, null, 0);
}
}
@ -49,13 +76,11 @@ public class JSONXMLParser {
* @param x {@link XMLTokener}
* @param context {@link JSONObject}
* @param name 标签名null表示从根标签开始解析
* @param parseConfig 解析选项
* @param currentNestingDepth 当前层级
* @return {@code true}表示解析完成
* @throws JSONException JSON异常
*/
private static boolean parse(final XMLTokener x, final JSONObject context, final String name,
final ParseConfig parseConfig, final int currentNestingDepth) throws JSONException {
private boolean parse(final XMLTokener x, final JSONObject context, final String name, final int currentNestingDepth) throws JSONException {
final char c;
int i;
final JSONObject jsonobject;
@ -155,9 +180,9 @@ public class JSONXMLParser {
throw x.syntaxError("Misshaped tag");
}
if (!jsonobject.isEmpty()) {
context.append(tagName, jsonobject);
context.append(tagName, jsonobject, this.predicate);
} else {
context.append(tagName, StrUtil.EMPTY);
context.append(tagName, StrUtil.EMPTY, this.predicate);
}
return false;
@ -185,13 +210,13 @@ public class JSONXMLParser {
}
// Nested element
if (parse(x, jsonobject, tagName, parseConfig, currentNestingDepth + 1)) {
if (parse(x, jsonobject, tagName, currentNestingDepth + 1)) {
if (jsonobject.isEmpty()) {
context.append(tagName, StrUtil.EMPTY);
context.append(tagName, StrUtil.EMPTY, this.predicate);
} else if (jsonobject.size() == 1 && jsonobject.get("content") != null) {
context.append(tagName, jsonobject.get("content"));
context.append(tagName, jsonobject.get("content"), this.predicate);
} else {
context.append(tagName, jsonobject);
context.append(tagName, jsonobject, this.predicate);
}
return false;
}

View File

@ -64,7 +64,7 @@ public class JSONXMLUtil {
* @since 5.3.1
*/
public static JSONObject toJSONObject(final String xmlStr, final JSONObject jo, final ParseConfig parseConfig) throws JSONException {
JSONXMLParser.parseJSONObject(xmlStr, jo, parseConfig);
JSONXMLParser.of(parseConfig, null).parseJSONObject(xmlStr, jo);
return jo;
}

View File

@ -0,0 +1,20 @@
package org.dromara.hutool.json;
import org.dromara.hutool.core.text.StrUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class IssueI9DX5HTest {
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@Test
void xmlToJSONTest() {
final String xml = "<GoodMsg>你好</GoodMsg>";
final JSONObject jsonObject = new JSONObject(xml, JSONConfig.of(), entry -> {
entry.setKey(StrUtil.toUnderlineCase(entry.getKey()));
return true;
});
Assertions.assertEquals("{\"good_msg\":\"你好\"}", jsonObject.toString());
}
}