#c# #json #.net #xml
Вопрос:
У меня есть несколько примеров 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
родительский тег.
Ответ №1:
Чтобы изменить формат ввода, вы должны сначала десериализовать 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:
Вот как я это решил. Сначала я создал классы 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);
Ответ №3:
Вы можете написать пользовательский XmlNodeConverter, который вставит родительский элемент, если текущий элемент является массивом. Например,
public class ArrayXmlNodeConverter : XmlNodeConverter
{
public readonly string _arrayRootName;
public ArrayXmlNodeConverter(string rootElement,string arrayRootName)
{
(DeserializeRootElementName,_arrayRootName) = (rootElement,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 (token.Type == JTokenType.Array)
{
var arrayHolder = new JObject { { _arrayRootName, token } };
token.Replace(arrayHolder);
}
else
{
foreach (var childToken in token)
{
ChangeArrayElementRoot(childToken);
}
}
}
}
Теперь вы могли бы использовать в качестве
var xml = (XmlDocument)JsonConvert.DeserializeObject(jsonString,
typeof(XmlDocument),
new ArrayXmlNodeConverter("tag","Property"));