从Java中的嵌入式JSON字符串中提取值-问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文

从Java中的嵌入式JSON字符串中提取值

我需要帮助将JSON数组字符串提取到对象数组中,以便稍后进行处理。

JSON字符串作为值嵌入在管道定界字符串中,该字符串本身就是XML元素值。

示例字符串如下

<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}</MSG>

如何提取JSON属性并将其存储在单独的数组中,例如

Format[0] =BMP
Position[0] =RIGHT_INDEX
Data[0]=Qk12WQEAAAAAADYAAAA =
Format[1] =BMP
Position[1]=LEFT_INDEX
Data[1]=Qk12WQEADoAAAA

然后将这些对象传递给一个单独的函数,如下所示

FingerprintImage(Format[0],Position[0],Data[0]);
// ...
FingerprintImage(Format[1],Position[1],Data[1]);
// ...

public FingerprintImage(String format, String position, String data) {
    setFormat(format);
    setPosition(position);
    setData(data);
}

问题来源:Stack Overflow

展开
收起
montos 2020-03-26 09:00:44 585 0
1 条回答
写回答
取消 提交回答
  • 我不是Java开发人员,以下内容希望对您自己或其他可以在Java中提供更简洁语法的人有所帮助。

    1. 首先,我们应确定与您的价值有关的数据序列化的不同层次: 这是一个外部XML元素,因此第一步是将该值解释为XML片段并提取XML值。
      • 之所以在此顶层使用XML反序列化,而不仅仅是使用字符串位置,是因为内部值可能已被 XML转义,因此我们需要使用XML编码规则来解析内部值。
      • 这给我们留下了strimg值:
        registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}
        
    2. 下一级别是管道定界的,与CSV相同,除了转义字符是a |并且通常没有其他编码规则,因为|这不属于常规词法域的一部分,我们不需要任何进一步的转义。 因此,您可以将此字符串拆分为一个数组。
      • 我们感兴趣的值是数组中的第15个元素,您可以事先知道,也可以简单地遍历这些元素以找到第一个以 {
      • 留下一个JSON值:
      {"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}
      
    3. 既然我们已经以JSON格式隔离了内部值,接下来要做的通常的事情就是将该值反序列化为一个对象。 我知道OP正在请求数组,但是如果我们真的想使用正确的工具,就可以将JSON对象实现为数组。

    在C#中,上面的过程非常简单,我确定它也应该在Java中,但是我的尝试不断抛出错误。

    因此,让我们假设(我知道... Ass-U-Me ...)在管道分隔的数组中只有一个JSON值,有了这个知识,我们可以使用以下方法隔离JSONint String.IndexOf(str)

    String xml = "<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{\"biometrics\":{\"fingerprints\":{\"fingerprints\":[{\"position\":\"RIGHT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEAAAAAADYAAAA=\"}},{\"position\":\"LEFT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEADoAAAA\"}}]}}}</MSG>";
    
    int start = xml.indexOf('{');
    int end = xml.lastIndexOf('}') + 1; // +1 because we want to include the last character, so we need the index after it
    
    String json = xml.substring(start, end);
    

    结果是:

    {"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}
    

    格式化为漂亮:

    {
      "biometrics": {
        "fingerprints": {
          "fingerprints": [
            {
              "position": "RIGHT_INDEX",
              "image": {
                "format": "BMP",
                "resolutionDpi": "508",
                "data": "Qk12WQEAAAAAADYAAAA="
              }
            },
            {
              "position": "LEFT_INDEX",
              "image": {
                "format": "BMP",
                "resolutionDpi": "508",
                "data": "Qk12WQEADoAAAA"
              }
            }
          ]
        }
      }
    }
    

    一种方法是创建一个与该JSON值匹配的类结构,然后我们可以简单地.fromJson()获取整个值,而让我们相约一半,因此我们只需要为将实际使用的数据定义内部类结构即可。

    现在,从该结构中,我们可以看到有一个外部对象,该对象仅具有一个称为的单个属性biometrics,该值再次是一个具有单个属性的名为的对象fingerprints。该属性的值是另一个具有单个属性的对象,fingerprints但这次它具有数组值。

    以下是Java的证明,我首先提供了一个使用序列化的示例(使用gson库),然后提供了仅使用simple-JSON库读取数组中值的类似实现。

    JDoodle.com上试用

    MyClass.java

    import java.util.*;
    import java.lang.*;
    import java.io.*;
    
    //import javax.json.*;
    import org.json.simple.JSONArray;
    import org.json.simple.JSONObject;
    import org.json.simple.parser.JSONParser;
    import org.json.simple.parser.ParseException;
    
    import com.google.gson.Gson;
    
    
    public class MyClass {
        public static void main(String args[]) {
    
            String xml = "<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{\"biometrics\":{\"fingerprints\":{\"fingerprints\":[{\"position\":\"RIGHT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEAAAAAADYAAAA=\"}},{\"position\":\"LEFT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEADoAAAA\"}}]}}}</MSG>";
    
            int start = xml.indexOf('{');
            int end = xml.lastIndexOf('}') + 1; // +1 because we want to include the last character, so we need the index after it
    
            String jsonString = xml.substring(start, end);
    
            JSONParser parser = new JSONParser();
            Gson gson = new Gson();
            try
            {
                // locate the fingerprints inner array using simple-JSON (org.apache.clerezza.ext:org.json.simple:0.4 )
                JSONObject jsonRoot = (JSONObject) parser.parse(jsonString);
                JSONObject biometrics = (JSONObject)jsonRoot.get("biometrics");
                JSONObject fpOuter = (JSONObject)biometrics.get("fingerprints");
                JSONArray fingerprints = (JSONArray)fpOuter.get("fingerprints");
    
                // Using de-serialization from gson (com.google.code.gson:gson:2.8.6)
    
                FingerPrint[] prints = new FingerPrint[fingerprints.size()];
                for(int i = 0; i < fingerprints.size(); i ++)
                {
                    JSONObject fpGeneric = (JSONObject)fingerprints.get(i);
                    prints[i] = gson.fromJson(fpGeneric.toString(), FingerPrint.class);
                }
    
                // Call the FingerprintImage function using the FingerPrint objects
                System.out.print("FingerPrint Object Index: 0");
                FingerprintImage(prints[0].image.format, prints[0].position, prints[0].image.data );
                System.out.println();
                System.out.print("FingerPrint Object Index: 1");
                FingerprintImage(prints[1].image.format, prints[1].position, prints[1].image.data );  
                System.out.println();
    
                // ALTERNATE Array Implementation (doesn't use gson)
                String[] format = new String[fingerprints.size()];
                String[] position = new String[fingerprints.size()];
                String[] data = new String[fingerprints.size()];
                for(int i = 0; i < fingerprints.size(); i ++)
                {
                    JSONObject fpGeneric = (JSONObject)fingerprints.get(i);
                    position[i] = (String)fpGeneric.get("position");
                    JSONObject image = (JSONObject)fpGeneric.get("image");
                    format[i] = (String)image.get("format");
                    data[i] = (String)image.get("data");
                }
    
                System.out.print("Generic Arrays Index: 0");
                FingerprintImage(format[0], position[0], data[0] );
                System.out.println();
                System.out.print("Generic Arrays Index: 1");
                FingerprintImage(format[1], position[1], data[1] ); 
                System.out.println();
            }
            catch (ParseException ignore) {
            }
    
    
        }
    
        public static void FingerprintImage(String format, String position, String data) {
            setFormat(format);
            setPosition(position);
            setData(data);
        }
        public static void setFormat(String format) {
            System.out.print(", Format=" + format);
        }
        public static void setPosition(String position) {
            System.out.print(", Position=" + position);
        }
        public static void setData(String data) {
            System.out.print(", Data=" + data);
        }
    }
    

    指纹软件

    public class FingerPrint {
        public String position;
        public FingerPrintImage image;   
    }
    

    FingerPrintImage.java

    public class FingerPrintImage {
        public String format;
        public int resolutionsDpi;
        public String data;
    }
    

    通常认为反序列化技术优于强制/手动解析,尤其是当我们需要传递对多个解析值的引用时。在上述示例中,通过简单地读取format,position并且data为单独的阵列,它们之间的关系已成为去耦合,通过我们的代码实现我们仍然可以一起使用它们,只要我们使用相同的数组索引,但结构不再限定值之间的关系。反序列化为类型化的结构可保留值之间的关系,并简化了传递彼此相关的值的任务。

    更新 如果使用序列化,则可以将等效FingerPrint对象传递给需要它的任何方法,而不是分别传递相关的值,此外,您可以简单地传递整个FingerPrint对象数组。

    public static void FingerprintImage(FingerPrint print) {
        setFormat(print.image.format);
        setPosition(print.position);
        setData(print.image.data);
    }
    

    要FingerPrint批量处理多个对象,请将方法更改为接受数组:FingerPrint[]

    您可以使用相同的技术来处理数组或每个数组Format,Postion以及Data,尽管这样做实在不明智。绕过多个数组并期望接收代码知道应该同步解释每个数组,也就是说,每个数组中的相同索引对应于相同的指纹,这种实现细节太模糊了,将导致为了维护正常的噩梦,学习和精通面向对象的概念以及创建用于传递相关数据元素的业务对象要好得多,而不是将所有内容打包到分离的数组中。

    以下代码可以帮助您使用OPs 数组方法处理多个项目,但应突出说明为什么此习惯是不习惯的习惯:

    public static void FingerprintImage(String[] formats, String[] positions, String[] datas) {
        // now you must iterate each of the arrays using the same index
        // however as there are no restrictions on the arrays, for each array 
        // and each index we should be checking that the array has not gone out
        // of length.
    }
    

    从面向对象的角度来看,像这样通过多个数组会引起很多问题,首先,开发人员将只需要知道必须在每个数组中使用相同的索引来检索相关信息。下一个重要的问题是错误处理...

    如果datas只有1个元素,但positions只有2个元素,那么1个data元素属于2个元素中的哪个?还是这表明data两者都应使用相同的符号?

    还有许多其他问题,请考虑何时需要3个元素... 虽然您确实可以逃避看起来像是快捷方式的代码,但除非您完全了解自己在做什么,否则就不应该这样做记录相关代码,您将对潜在的后果负责。

    回答来源:Stack Overflow

    2020-03-26 09:12:07
    赞同 展开评论 打赏
问答排行榜
最热
最新
相关课程
更多
相关电子书
更多
JAVA开发手册1.5.0
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
相关实验场景
更多