JSON.Net Xml Сериализация неправильно понимает массивы
У меня есть некоторые автогенерируемые xmls, где некоторые части xml могут иметь несколько строк, а некоторые – нет. В результате, если есть одна строка, возвращается один json-узел, и если у меня есть несколько строк, возвращается массив с json-узлами.
Xmls может выглядеть так:
Testing 0
Или с несколькими строками
- ТипNameHandling предостережение в Newtonsoft Json
- JSON.NET Parser * кажется * будет двойной сериализацией моих объектов
- Сериализация нулевого значения в JSON.NET
- Использование преобразователей Json.NET для десериализации свойств
- В чем разница между PreserveReferencesHandling и ReferenceLoopHandling в Json.Net?
Update Documentation 0.5 2013-01-31 00:00:00 2013-01-01 00:00:00 Write jQuery example 0.05 2013-06-30 00:00:00 2013-01-02 00:00:00
При их сериализации с использованием JSON
JsonConvert.SerializeXmlNode(xmldoc, Formatting.Indented);
Первый xml становится
{ "List": { "Content": { "Row": { "@Index": "0", "Title": "Testing", "PercentComplete": "0", "DueDate": null, "StartDate": null } } } }
И второе
{ "List": { "Content": { "Row": [{ "@Index": "0", "Title": "Update Documentation", "PercentComplete": "0.5", "DueDate": "2013-01-31 00:00:00", "StartDate": "2013-01-01 00:00:00" }, { "@Index": "1", "Title": "Write jQuery example", "PercentComplete": "0.05", "DueDate": "2013-06-30 00:00:00", "StartDate": "2013-01-02 00:00:00" }] } } }
Как ясно видно, строка на втором является массивом, который должен быть, но не первым. Существует ли какое-либо известное обходное решение для такого рода проблем или мне нужно выполнить проверку в моем интерфейсе, получая JSON (это было бы немного проблематично, поскольку структуры очень динамичны). Лучше всего было бы, если бы там, где любой способ принудить json.net всегда возвращать массивы.
- Json.net сериализует определенное частное поле
- Разбор JSON в C #
- Json.NET (Newtonsoft.Json) - Два «свойства» с таким же именем?
- Json.Net: свойство Serialize / Deserialize в качестве значения, а не как объект
- JSON.net сериализуется непосредственно из oledbconnection
- Сериализация типа Json.Net с полиморфным дочерним объектом
- Как обрабатывать как отдельный элемент, так и массив для одного и того же свойства с помощью JSON.net
- Как я могу десериализовать JSON для простого словаря в ASP.NET?
Из документации Json.NET: http://james.newtonking.com/projects/json/help/?topic=html/ConvertingJSONandXML.htm
Вы можете заставить узел быть рендером в виде массива, добавив атрибут json:Array='true'
к узлу XML, который вы конвертируете в JSON. Кроме того, вам нужно объявить пространство имен префиксов json в заголовке XML xmlns:json='http://james.newtonking.com/projects/json'
иначе вы получите сообщение об ошибке XML, в котором указано, что префикс json не объявлен.
Следующий пример представлен документацией:
xml = @" Alan http://www.google.com Admin ";
Сгенерированный выход:
{ "person": { "@id": "1", "name": "Alan", "url": "http://www.google.com", "role": [ "Admin" ] } }
Я исправил это поведение, как это
// Handle JsonConvert array bug var rows = doc.SelectNodes("//Row"); if(rows.Count == 1) { var contentNode = doc.SelectSingleNode("//List/Content"); contentNode.AppendChild(doc.CreateNode("element", "Row", "")); // Convert to JSON and replace the empty element we created but keep the array declaration returnJson = JsonConvert.SerializeXmlNode(doc).Replace(",null]", "]"); } else { // Convert to JSON returnJson = JsonConvert.SerializeXmlNode(doc); }
Это немного грязно, но это работает. Меня все еще интересуют другие решения!
Предоставляя мой +1 Ивану Пересу Гомесу и предоставляя код здесь, чтобы поддержать его ответ:
Добавьте требуемое пространство имен json.net в корневой узел:
private static void AddJsonNetRootAttribute(XmlDocument xmlD) { XmlAttribute jsonNS = xmlD.CreateAttribute("xmlns", "json", "http://www.w3.org/2000/xmlns/"); jsonNS.Value = "http://james.newtonking.com/projects/json"; xmlD.DocumentElement.SetAttributeNode(jsonNS); }
И добавить атрибут json: Array к элементам, найденным xpath:
private static void AddJsonArrayAttributesForXPath(string xpath, XmlDocument doc) { var elements = doc.SelectNodes(xpath); foreach (var element in elements) { var el = element as XmlElement; if (el != null) { var jsonArray = doc.CreateAttribute("json", "Array", "http://james.newtonking.com/projects/json"); jsonArray.Value = "true"; el.SetAttributeNode(jsonArray); } } }
Вот пример одного дочернего узла как json-массив:
Мое решение: если JsonConvert не работает, не используйте его. Разбирайте XML в словари / коллекции, а затем в Json. По крайней мере, таким образом вам не нужно жестко кодировать любые имена элементов.
private JsonResult AsJsonResult(XmlDocument result) { var kvp = new KeyValuePair(result.DocumentElement.Name, Value(result.DocumentElement)); return Json(kvp , JsonRequestBehavior.AllowGet); } /// /// Deserializing straight from Xml produces Ugly Json, convert to Dictionaries first to strip out unwanted nesting /// /// /// private object Value(XmlNode node) { dynamic value; //If we hit a complex element if (node.HasChildNodes && !(node.FirstChild is XmlText)) { //If we hit a collection, it will have children which are also not just text! if (node.FirstChild.HasChildNodes && !(node.FirstChild.FirstChild is XmlText)) { //want to return a list of Dictionarys for the children's nodes //Eat one level of the hierachy and return child nodes as an array value = new List
Обнаружена такая же проблема с использованием XDocument
if (XDocument.Parse («5.0021.0045.00»). Потомки («строка»). Count ()> 1) {}
if (XDocument.Parse("1.00 5.00 45.00 |
6.00 10.00 65.00 |
11.00 100.00 98.00 |
").Descendants("row").Count() > 1) { }