У меня есть образец JSON в этом формате:

{
    "id": "532-513jg-5ujkl-5jiklf",
    "externalGuid": "93804jlkfes",
    "tagNumber": "2KMA",
    "project": {
        "id": "532kg-fw13jg-553klal-5jiklf",
        "projectName": "Test",
        "projectId": "1"
    },
    "properties": [
        {
            "id": "jkl39-jkl39084-agd208-hh82a9",
            "name": "Weight",
            "value": "1000",
            "statusCode": {
                "name": "Accepted",
                "code": 1
            }
        },
        {
            "id": "jkl39-jkl384-123208-hh82a9",
            "name": "Length",
            "value": "10",
            "statusCode": {
                "name": "Not Accepted",
                "code": 3
            }
        }
    ]
}

Я хочу преобразовать это в XML, поэтому делаю следующее: XmlDocument node = JsonConvert.DeserializeXmlNode(jsonString, "tag"); Это дает мне следующий XML:

<tag>
  <id>532-513jg-5ujkl-5jiklf</id>
  <externalGuid>93804jlkfes</comosUID>
  <tagNumber>2KMA</tagNumber>
  <project>
    <id>532kg-fw13jg-553klal-5jiklf</id>
    <projectName>Test</projectName>
    <projectId>1</projectId>
  </project>
  <properties>
    <id>jkl39-jkl39084-agd208-hh82a9</id>
    <name>Weight</name>
    <value>1000</value>
    <statusCode>
      <name>Accepted</name>
      <code>1</code>
    </statusCode>
  <properties>
    <id>jkl39-jkl384-123208-hh82a9</id>
    <name>Length</name>
    <value>10</value>
    <statusCode>
      <name>Not Accepted</name>
      <code>3</code>
    </statusCode>
  </properties>
</tag>

Что ПОЧТИ то, что я хочу. Однако система, которая будет импортировать XML, ожидает немного другого формата. Он хочет, чтобы каждое из свойств начиналось и заканчивалось тегом <property>. Итак, массив свойств будет выглядеть так:

<properties>
  <property>
    <id>jkl39-jkl39084-agd208-hh82a9</id>
    <name>Weight</name>
    <value>1000</value>
    <statusCode>
      <name>Accepted</name>
      <code>1</code>
    </statusCode>
  </property>
  <property>
    <id>jkl39-jkl384-123208-hh82a9</id>
    <name>Length</name>
    <value>10</value>
    <statusCode>
      <name>Not Accepted</name>
      <code>3</code>
    </statusCode>
  </property>
</properties>

Как мне сделать так, чтобы XML соответствовал этому шаблону? То есть замените теги properties на property и заключите все теги property в родительский тег properties.

2
PalBo 15 Сен 2021 в 13:34

3 ответа

Лучший ответ

Чтобы изменить формат вашего ввода, вы должны сначала десериализовать JSON до соответствующей модели, затем вы можете использовать System.Xml.Linq для экспорта узлов в том порядке и структурировании, как вы хотите.

Model model = JsonConvert.DeserializeObject<model>(jsonString);
var xml = new XElement("properties", 
               new XElement("property",
                  new XElement("id", model.Id),
                  new XElement("name", model.Name) /*and so on*/));

Кажется, что написано много, но вы действительно можете делать с XML все, что захотите. Вы можете подготовить методы обработки модели и настроить ее, но это зависит от ваших требований.

Вы также можете создать другую модель со структурой, соответствующей структуре XML-файла, которую вам затем нужно будет заполнить данными из исходного узла, но это выглядит как много ненужной работы. Я лично буду использовать System.Xml.Linq для такой задачи.

2
Adam Kaczmarski 15 Сен 2021 в 11:44

Вот как я это решил. Сначала я создал классы C # для соответствующих элементов JSON / XML:

    [XmlRoot("tag")]
    [JsonObject(Title = "tag")]
    public class Tag
    {
        [XmlElement("id")] public string Id { get; set; }
        [XmlElement("externalGuid")] public string ExternalGuid{ get; set; }
        [XmlElement("tagNumber")] public string TagNumber { get; set; }
        [XmlElement("project")] public Project Project { get; set; }
        [XmlArray("properties")] public List<Property> Properties { get; set; }
    }

    [XmlType("property")]
    public class Property
    {
        [XmlElement("id")] public string Id { get; set; }
        [XmlElement("name")] public string Name { get; set; }
        [XmlElement("value")] public string Value { get; set; }
        [XmlElement("status")] public Status Status { get; set; }
    }

    public class Status
    {
        [XmlElement("id")] public string Id { get; set; }
        [XmlElement("name")] public string Name { get; set; }
        [XmlElement("code")] public int Code { get; set; }
    }

    public class Project
    {
        [XmlElement("id")] public string Id { get; set; }
        [XmlElement("projectName")] public string ProjectName { get; set; }
        [XmlElement("projectId")] public string ProjectId { get; set; }
    }

Затем я реализовал собственный конвертер Json в XML:

        public static string TransformJsonToXml<T>(string json)
        {
            var jsonObjectAttribute = typeof(T).GetCustomAttribute(typeof(JsonObjectAttribute)) as JsonObjectAttribute;
            JObject root = JObject.Parse(json);
            var data = root[jsonObjectAttribute.Title];

            var obj = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(data));

            var serializer = new XmlSerializer(typeof(T));
            var stringWriter = new StringWriter();
            using var xmlWriter = XmlWriter.Create(stringWriter);
            var xmlSerializerNamespaces = new XmlSerializerNamespaces();
            xmlSerializerNamespaces.Add("","");
            serializer.Serialize(xmlWriter, obj, xmlSerializerNamespaces);
            return stringWriter.ToString();
        }

Теперь преобразовать JSON в XML просто: var xml = TransformJsonToXml<Tag>(jsonInput);

1
PalBo 15 Сен 2021 в 13:01

Вы можете написать собственный XmlNodeConverter, который будет вставлять родительский элемент, если текущий элемент является массивом. Например,

public class ArrayXmlNodeConverter : XmlNodeConverter
{
    public readonly string _arrayRootName;

    public ArrayXmlNodeConverter(string arrayRootName)
    {
        _arrayRootName = arrayRootName;
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JObject.Load(reader);
        ChangeArrayElementRoot(token);
        reader = token.CreateReader();
        reader.Read();
        return base.ReadJson(reader, objectType, existingValue, serializer);
    }

    private void ChangeArrayElementRoot(JToken token)
    {
         // If it is an array, insert parent element
        if (token.Type == JTokenType.Array)
        {
            var arrayHolder = new JObject { { _arrayRootName, token } };
            token.Replace(arrayHolder);
        }
        else
        {
            // check iteratively
            foreach (var childToken in token)
            {
                ChangeArrayElementRoot(childToken);
            }
        }
    }
}

Теперь вы можете использовать как

var xml = (XmlDocument)JsonConvert.DeserializeObject(jsonString,
                   typeof(XmlDocument), 
                   new ArrayXmlNodeConverter("tag","Property"));

Демо-код

0
Anu Viswan 15 Сен 2021 в 12:22