избавиться от @ и # при преобразовании XML в JSON с c # [duplicate]

Указатель NULL - это тот, который указывает на никуда. Когда вы разыскиваете указатель p, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p является нулевым указателем, местоположение, хранящееся в p, является nowhere, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception.

В общем, это потому, что что-то не было правильно инициализировано.

10
задан Alexander 8 October 2014 в 19:40
поделиться

9 ответов

Я пошел вперед и использовал это. Дайте мне знать, если есть лучший способ.

public ActionResult Layout()
{
    var xml = new XmlDocument();
    xml.XmlResolver = null;
    xml.Load(Server.MapPath("~/App_Data/Navigation.xml"));

    var jsonText = JsonConvert.SerializeXmlNode(xml, Newtonsoft.Json.Formatting.Indented);
    return Content(Regex.Replace(jsonText, "(?<=\")(@)(?!.*\":\\s )", string.Empty, RegexOptions.IgnoreCase));
}
9
ответ дан Alexander 17 August 2018 в 15:21
поделиться
  • 1
    Вы знаете, что это единственное место, где появятся знаки @ в json, string.replace работает намного быстрее или больше документов – andryuha 10 July 2012 в 22:35
  • 2
    Как уже упоминалось @yieio, это все еще не работает для значений, начинающихся с @, например. <test attr="@foo" /> приведет к {"test":{"attr":"foo"}}. – Aristoteles 22 July 2013 в 11:26
  • 3
    Это не хорошо для производительности. Было бы лучше создать пользовательский JsonTextWriter, как было сказано в другом месте здесь. – Alex Angas 4 April 2018 в 11:42

Другой вариант - создать собственный OneWayXmlNodeConverter, наследующий от JsonConverter, и вызвать SerializeObject вместо SerializeXmlNode следующим образом:

var json = JsonConvert.SerializeObject(xmlNode, new OneWayXmlNodeConverter());

Я называю это «One Way», потому что я предположим, что по умолчанию XmlNodeConverter добавляет знак «@», чтобы он мог преобразовать обратно в XML из результирующего JSON.

Если вы включили источник JSON.NET в свой проект (в отличие от только скомпилированной библиотеки ), простой способ создать OneWayXmlNodeConverter - скопировать код XmlNodeConverter, удалить жестко закодированный знак «@» в личном GetPropertyName методе и сохранить его как OneWayXmlNodeConverter.

Примечание. Я знаю, что ваш вопрос специфичен для «замены» знака «@», но связанный вариант Предотвращение этого вопроса отмечен как дубликат.

1
ответ дан Community 17 August 2018 в 15:21
поделиться
  • 1
    Ваше предложение очень интересно, но вы его попробовали? Когда я попытался скопировать код XmlNodeConverter, я обнаружил, что он сильно зависит от внутренних интерфейсов и классов. Поэтому я не смог сделать то, что вы предложили. Вам удалось заставить его работать? – Pola Edward 5 July 2015 в 15:50
  • 2
    @PolaEdward Я включил исходный код Json.Net в свой проект, поэтому я смог использовать внутренние компоненты. Я буду обновлять свой ответ, потому что вы правы, если вы просто используете библиотеку, это легко not :-) – dalenewman 6 July 2015 в 13:26
  • 3
    Отлично, обновление ответов всегда рекомендуется :) На самом деле я закончил тем, что понял, что мне нужно внедрить код newtonsoft, чтобы иметь возможность редактировать его, придерживаться определенной версии и потерять все будущие обновления от автора, или с помощью регулярного выражения, Я решил использовать регулярное выражение – Pola Edward 7 July 2015 в 10:30

Мне потребовалось довольно много времени, чтобы найти правильный ответ, поэтому я решил поделиться:

var xDocument = XDocument.Parse("<xml><a attr=\"b\">c</a></xml>");
var builder = new StringBuilder();
JsonSerializer.Create().Serialize(new CustomJsonWriter(new StringWriter(builder)), xDocument);
var serialized = builder.ToString();

public class CustomJsonWriter : JsonTextWriter
{
    public CustomJsonWriter(TextWriter writer): base(writer){}

    public override void WritePropertyName(string name)
    {
        if (name.StartsWith("@") || name.StartsWith("#"))
        {
            base.WritePropertyName(name.Substring(1));
        }
        else
        {
            base.WritePropertyName(name);
        }
    }
}

Выход:

{"xml":{"a":{"attr":"b","text":"c"}}}
13
ответ дан Ilya 17 August 2018 в 15:21
поделиться
  • 1
    Это самое правильное и простейшее решение ... Переопределенный конвертер займет гораздо больше работы, чтобы рассмотреть все случаи. – Maxim 6 August 2017 в 12:49
  • 2
    – N. Kudryavtsev 7 September 2018 в 12:58
  • 3
    – N. Kudryavtsev 7 September 2018 в 15:07

Если JSON имеет отступ, это может работать:

Regex.Replace(result, @"(\s*)""@(.*)"":", @"$1""$2"":", RegexOptions.IgnoreCase);
1
ответ дан miken32 17 August 2018 в 15:21
поделиться
  • 1
    Подтверждено, что оно не влияет на @ символов в содержимом атрибутов, либо в начале, в середине, либо в конце. – Mr. Bungle 18 May 2017 в 01:25
  • 2
    Да, но из-за этого вы теряете производительность при получении атрибута JSON – Jacks 8 August 2017 в 09:52
  • 3
    Подход с регулярным выражением не подходит для производительности и, возможно, глючит. – Alex Angas 4 April 2018 в 12:20

Прошло некоторое время с момента ответа, но это может помочь кому-то. Поскольку у вас уже есть XMLDocument, вы можете удалить и преобразовать атрибуты перед его сериализацией. Я попытался либо удалить атрибуты, либо преобразовать их в элементы.

public static void RemoveAllAttributes(XmlDocument xmlDocument)
{
     if (xmlDocument == null || !xmlDocument.HasChildNodes) return;

     foreach (var xmlElement in xmlDocument.SelectNodes(".//*").Cast<XmlElement>().Where(xmlElement => xmlElement.HasAttributes))
     {
          xmlElement.Attributes.RemoveAll();
     }
}

public static void ElementifyAllAttributes(XmlDocument xmlDocument)
{
    if (xmlDocument == null || !xmlDocument.HasChildNodes) return;

    foreach (var xmlElement in xmlDocument.SelectNodes(".//*").Cast<XmlElement>().Where(xmlElement => xmlElement.HasAttributes))
    {
        foreach (XmlAttribute xmlAttribute in xmlElement.Attributes)
        {
            xmlElement.AppendChild(xmlDocument.CreateElement(xmlAttribute.Name)).InnerText = xmlAttribute.Value;
        }

        xmlElement.Attributes.RemoveAll();
     }
}

И затем;

private static string XmlToJson(XmlDocument xmlDocument)
{
    if (xmlDocument == null) return null;

    //Remove xml declaration
    xmlDocument.RemoveChild(xmlDocument.FirstChild);

    //Convert attributes to elements
    ElementifyAllAttributes(xmlDocument);

    return JsonConvert.SerializeXmlNode(xmlDocument, Formatting.None, false);
}
1
ответ дан omufeed 17 August 2018 в 15:21
поделиться

Сначала замените все «@» в вашем xml-содержимом некоторым заполнителем (в качестве примера {{at_the_rate}}). Затем используйте ниже код

JsonConvert.SerializeXmlNode(doc).Replace("@", "").Replace("{{at_the_rate}}", "@")
-1
ответ дан Pang 17 August 2018 в 15:21
поделиться
  • 1
    Надеюсь, вы поймете, что произойдет, если ваши данные имеют «{{at_the_rate}}». – Maxim 6 August 2017 в 12:50

Я предлагаю использовать следующее регулярное выражение, это то же самое, что и @yieio, но улучшать, чтобы оставить содержимое без изменений и влиять только на имена свойств

var jString = Regex.Replace(
JsonConvert.SerializeXmlNode(content, Newtonsoft.Json.Formatting.None, true),
 "(?<=(\\,\\\"|\\{\\\"))(@)(?!.*\\\":\\\\s )", String.Empty, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
0
ответ дан Pola Edward 17 August 2018 в 15:21
поделиться
  • 1
    Когда я это пробовал, он не работает, т.е. похоже, ничего не изменило. & lt; test attr = "foo" / & GT; приводит к {& quot; test & quot;: {& quot; @ attr ":" foo & quot;}}. – A_L 26 January 2016 в 11:19
  • 2
    Подход с регулярным выражением не подходит для производительности и, возможно, глючит. – Alex Angas 4 April 2018 в 12:20

Regex не всегда работает отлично, когда контент имеет символ @ и, в первую очередь, это тоже будет заменено. поэтому я думаю, что (?<!:)(\"@)(?!.\":\\s ) может быть лучше.

1
ответ дан yieio 17 August 2018 в 15:21
поделиться
  • 1
    Это все еще не работает для значений, начинающихся с "@, например. <test attr="&quot;@foo" /> приведет к {"test":{"attr":"\"foo"}}. – Aristoteles 22 July 2013 в 11:25
  • 2
    @Aristoteles Проверьте мое регулярное выражение, оно основано на вышесказанном, но не изменяет содержимое – Pola Edward 7 July 2015 в 10:41
  • 3
    Подход с регулярным выражением не подходит для производительности и, возможно, глючит. – Alex Angas 4 April 2018 в 12:20

Если вы хотите получить доступ к значению атрибута из-за знака «@», выполните следующие действия:

Navigation["@Type"]
1
ответ дан miken32 17 August 2018 в 15:21
поделиться
  • 1
    Да, но из-за этого вы теряете производительность при получении атрибута JSON – Jacks 8 August 2017 в 09:52
Другие вопросы по тегам:

Похожие вопросы: