【问题标题】:Is there a way to Serialize Json that contains a field that contains more json as a string to XML有没有一种方法可以序列化包含一个包含更多 json 作为 XML 字符串的字段的 Json
【发布时间】:2019-09-18 09:26:28
【问题描述】:

我从外部来源接收 Json 数据。我需要将 Json 消息转换为 XML。

这个使用NewtonSoft库比较简单:

        var placeHolder = $"{{\"Data\":  {jsonContent} }} ";
        var xmlNode = JsonConvert.DeserializeXmlNode(placeHolder, "Root").OuterXml;
        var doc = new XmlDocument();
        doc.LoadXml(xmlNode);

我收到的 Json 有一点奇怪的事情破坏了整个过程。

Json 看起来像这样:

[
  {
    "Type": "Application",
    "Object": {
      "Duration": 2,
      "Request": {
        "authReference": "..",
        "IdEnrolment": {
          "username": "test",
          "password": "***",
          "createNewUser": false
        }
      },
      "Type": "XXX.SomeController",
      "Logs": [

      ],
      "Method": "IdEnrolments",
      "Response": {
        "IdUsername": null,
        "result": {
          "resultCode": 0,
          "resultTitle": null,
          "resultMessage": null
        }
      }
    }
  },
  {
    "Type": "Proxy",
    "Object": {
      "Assembly": null,
      "Policy": null,
      "Cache": null,
      "Duration": 516,
      "Request": "{\"AuthenticateUserRequest\":{\"EnterpriseContext\":{\"ContextInfo\":{\"@xmlns\":\"http://example.xom\",\"ProcessContextId\":\"adad\",\"ExecutionContextId\":\"adac\"}\"}}",
      "Type": "https://someserver/services/ent/informationandtechnologymanagement/company/v1",
     "Logs": [

      ],
      "Method": "AuthenticateUser",
      "Response": "{\"AuthenticateUserResponse\":{\"EnterpriseContext\":{\"ContextInfo\":{\"@xmlns\":\"http://example.com\",\"ProcessContextId\":\"adad\",\"ExecutionContextId\":\"adad\"}}}}"
    }
  }
]

数组中的第一个对象是完美的并且可以正确序列化。数组中的第二个对象会导致混乱(可以理解)。此对象的请求和响应字段实际上是字符串,它们包含 JSON 代码。

有没有办法正确反序列化?我意识到要求图书馆足够灵活地做到这一点是很多事情 - 但我只是对如何使用它有点困惑。

我收到的所有消息看起来都大致相同 - 但具体而言,请求和响应对象的内容根据具体的请求/响应而有所不同。

构建这个的人没有任何类型的架构或合同,除了他们发送 Json 文本而且他们似乎不愿意或无法更改 Json 的创建方式。

任何建议都将不胜感激。

注意:这种行为似乎不是随机的。我得到的是正确的对象还是字符串由属性决定:“Type”:“Application”。有许多不同的“类型” - 有些是正确序列化的,有些则不是...... Aaarrggghhhh !!!!沮丧!!!!

【问题讨论】:

  • 正确反序列化 正确是什么意思?正如您已经说过的,Request 是一个包含 json 的字符串,因此正确地将其反序列化为一个字符串。如果你想把这个字符串变成一个对象,那么你需要在那个字符串上运行第二次反序列化
  • 有许多库可以将 XML 转换为 JSON,反之亦然。他们的做法都略有不同,而且在所有可能的情况下,他们都没有完全按照您的意愿行事。您需要习惯这样的想法,即您必须通过预处理输入或后处理输出来自定义转换。
  • @Liam,从技术上讲,您将字符串反序列化为字符串是正确的,但该字段是字符串,因为有人错误地构建了 JSON 以配合使用。所以,我对“正确”的看法是对象视图。这就是 JSON“应该看起来像”的样子。我并没有对序列化程序进行抨击,我实际上只是在寻找解决方案。
  • @Michael Kay,我希望众多 JSON 序列化程序之一可能已经处理了这个问题,但是,预处理和双序列化方法可能是唯一的选择。如果更聪明的人有更好的主意,我只是不想这样做……谢谢大家的回复。非常感谢。
  • 那么答案是首先正确地“构建 JSON”

标签: c# json xml json.net


【解决方案1】:

您的 JSON 在 root/Type:Proxy/Object/ 中被阻塞,请求嵌套格式错误:

 "Request": "{\"AuthenticateUserRequest\":{\"EnterpriseContext\":{\"ContextInfo\":{\"@xmlns\":\"http://example.xom\",\"ProcessContextId\":\"adad\",\"ExecutionContextId\":\"adac\"}\"}}",

这里有 4 个大括号打开,但只有 3 个关闭。

【讨论】:

  • 当我将非常大的 JSON 消息缩减为可以发布的内容时,这只是我的一个错字,所以大括号不是问题,反序列化才是问题。
  • @MulciberCoder 你知道用来序列化 JSON 的工具包是什么吗?如果你这样做,我建议你使用它来反序列化 JSON,因为许多 TK 的工作方式彼此略有不同,所以你有时会遇到无法反序列化 JSON 的情况。 (对不起我之前的错误答案)
  • @MulciberCoder 我注意到在一个示例中,请求以字符串的形式给出,而在另一个示例中,它是 JSON 对象……您需要为此创建两个单独的结构,然后解析再次指定结构。此外,您还必须以某种方式处理 XXX.SomeController,因为它不是合法的“类型”,因为您可以为每个“X”输入任何数字
【解决方案2】:

您必须处理的 JSON 非常非常不规则且很糟糕,因此您只需将所有这些解构为 C# 接口、类和结构,如下所示:

#region Fields
enum JsonObjType 
{
    Application,
    Proxy,
    SomeController,
}
#endregion

#region Classes
// Application
public class AppObj : JsonObjMaster
{
    public readonly JsonObjType Type_Ind {get;}
    public int Duration {get; set;}
    public AppRequest Request {get; set;}
    public AppObjController Controller {get; set;}

    //you need a default constuctor for classes, cause else no json parser will work with them
    public AppObj()
    {
        Type_Ind = JsonObjType.Application;
        Duration = 0;
        AppResult = String.Empty;
        Request = new AppRequest();
        Controller = new AppObjController();
    }
}

public class AppObjController : JsonObjSlave
{
    public readonly JsonObjType Type_Ind {get;}
    public string[] Logs {get; set;}
    public Func</*whatever is supposed to be here*/> Method {get; set;}
    public AppResult Result {get; set;}

    public AppObjController()
    {
        Type_Ind = JsonObjType.SomeController;
        Log = Array.Empty<string>();
        Method = (/*whatever is supposed to be here*/) => null; //may need to change depending on what the function is for
        Result = new AppResult();
    }
}

// Proxy
public class ProxyObj : JsonObjMaster
{
    public readonly JsonObjType Type_Ind {get;}
    public int Duration {get; set;}
    public string Assembly {get; set;}  //I am assuming strings here since no type is supplied
    public string Policy {get; set;}
    public string Cache {get; set;}
    public string Request {get; set;}
    public string Type {get; set;}
    public string[] Logs {get; set;}
    public Func</*whatever is supposed to be here*/> Method {get; set}
    public string Response {get; set;}

    public ProxyObj()
    {
        Type_Ind = JsonObjType.Proxy;
        Duration = 0; //not needed but to stay consistent
        Assembly = String.Empty();
        Policy = String.Empty();
        Cache = String.Empty();
        Request = String.Empty();
        Type = String.Empty();
        Logs = Array.Empty<string>();
        Method = (/*whatever is supposed to be here*/) => null; //may need to change depending on what the function is for
        Response = String.Empty();
    }
}
#endregion

#region Structs
// Interfaces
public interface JsonObjMaster
{
    public readonly JsonObjType Type_Ind {get;}
    public int Duration {get; set;}
}

public interface JsonObjSlave
{
    public readonly JsonObjType Type_Ind {get;}
}

// Structs
public struct IdEnrolment
{
    public string Username {get; set;}
    public string Password {get; set;}
    public bool CreateNewUser {get; set;}
}

public struct AppResult
{
    public int Code {get; set;}
    public string Title {get; set;}
    public string Message {get; set;}
}

public struct AppRequest
{
    public string AuthRefernece {get; set;}
    public IdEnrolment {get; set;}
}
#endregion

为了将 JSON 加载到类中,您现在需要在 JSON 文件的上下文中向解析器提供 C# 对象属性的名称,以便解析器可以链接它们。这可能看起来像这样:

[MyJsonparser.JsonName("Type")]
public string Type {get; set;}

但它高度依赖于您使用的 JSON 库,因此您需要在他们的文档中查找它。

如果您可以成功地将某人(希望不是您)所做的 JSON 操作转换为 C# 对象,那么您可以通过移动到另一层类和结构来解析剩余的 JSON 字符串,然后您可以将其用于处理。

现在,当您将 JSON 作为 C# 对象后,您可以轻松地将其序列化为 XML,但遗憾的是,由于 JSON 的实现方式非常糟糕,如果不使用 C# 对象作为元介质,您将无法自动执行此操作。

【讨论】:

  • 同意。理想情况下,我会定义强类型对象,然后序列化进出它们(即使我必须解析两次)。不幸的是,一个领域已经包含了 1500 种不同的结构。所以,我必须有成千上万的 POCO 小课程。在这种情况下,我需要实现的只是将 json 转换为 xml - 所以即使我构建了这些类,我也不会将它们用于其他任何事情。此外,它打破了灵活性的想法。如果已经有 1500 个不同的结构,那么几天后可能会出现 1501 个。
  • 卡兰南特。仅供参考....完全同意这个Json有多糟糕,不 - 我没有创造它。我制造的混乱往往更具创新性......
  • @MulciberCoder 我刚刚想到的是,您还可以将 JSON 反序列化为对象,然后有一个过滤器功能,该功能可以使用类型字符串接收每个字段,然后告诉它是否需要额外的反序列化,基于名称模式和您能找到的任何内容。然后取原始 JSON 并将字符串替换为实际对象并再次反序列化。之后,您可以再次将整个事件序列化为 XML
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
相关资源
最近更新 更多