开发者

JSON.NET and Replacing @ Sign in XML to JSON converstion

The JSON.NET framework can convert XML to JSON, but it uses the @ sign in the JSON as the attribute. I would rather remove this before sending it to the view. What would be the best approach for this?

I know I can do a straight up replace, but an @ character may be relevant somewhere and shouldn't be replaced. Is there a Regex for this?

public ActionResult Layout()
{
    var xml = new XmlDocument();
    xml.XmlResolver = null;
    xml.Load(Server.MapPath("~/App_Data/Navigation.xml"));
    return Content(JsonConvert.SerializeXmlNode(xml, Newtonsoft.Json.Formatting.Indented));
}
{
  "Layout": {
  开发者_如何学编程  "Navigation": [
      {
        "@Type": "Menu",
        "@Title": "Dashboard"
      },
      {
        "@Type": "Menu",
        "@Route": "Events",
        "@Title": "Events",
        "Navigation": {
          "@Type": "Action",
          "@Route": "Event",
          "@Title": "+ Add Event",
          "@Order": "1",
          "Navigation": {
            "@Type": "Item",
            "@Route": "Event",
            "@Name": "Event",
            "Navigation": [
              {
                "@Route": "Pools",
                "@Type": "SubNavigation",
                "@Name": "Pools"
              },
              {
                "@Route": "Brackets",
                "@Type": "SubNavigation",
                "@Name": "Brackets"
              }
            ]
          }
        }
      }
    ]
  }
}


It took me quite a while to find the right answer, so I thought I'd share:

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);
        }
    }
}

Output:

{"xml":{"a":{"attr":"b","text":"c"}}}


I went ahead and used this. Let me know if there is a better way.

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));
}


The Regex not always work great,when content has the @ character and in the first place,that will be replace too. so I think(?<!:)(\"@)(?!.\":\\s ) may be better.


Another option is to create your own OneWayXmlNodeConverter inheriting from JsonConverter and call SerializeObject instead of SerializeXmlNode like this:

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

I call it "One Way" because I assume the default XmlNodeConverter adds the "@" sign so it can convert back to XML from the resulting JSON.

If you include the JSON.NET source in your project (as opposed to just the compiled library), an easy way to create the OneWayXmlNodeConverter is to copy the XmlNodeConverter code, remove the hard-coded "@" sign in the private GetPropertyName method, and save it as OneWayXmlNodeConverter.

Note: I know that your question is specific to "replacing" the "@" sign, but the linked Preventing variation of this question is marked as duplicate.


Has been a while since this response, but this may still help someone. Since you already have the XMLDocument, you can remove and convert the attributes before serializing it. I tried by either removing the attributes or converting them to elements.

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();
     }
}

And then;

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);
}


If you want to access the value of an attribute because of the '@' sign, do the following:

Navigation["@Type"]


This is my regex contribution, using lookaheads and lookbehinds to ensure it only occurs in the attribute field

(?m)(?<=^\s+\")(@)(?=.+\"\:)

Breakdown:

(?m) - Run in multiline mode

(?<=^\s+\") - Lookbehind to find the beginning of the line, one or more spaces, and a quote symbol

(@) - Match the @ after the quote

(?=.+\"\:) - Look ahead to match any character at least once, followed by another quote and then a colon


I suggest using the following regex, it the same as @yieio provided, but enhance to leave the content as is without any modifications, and affect only property names

var jString = Regex.Replace(
JsonConvert.SerializeXmlNode(content, Newtonsoft.Json.Formatting.None, true),
 "(?<=(\\,\\\"|\\{\\\"))(@)(?!.*\\\":\\\\s )", String.Empty, System.Text.RegularExpressions.RegexOptions.IgnoreCase);


If the JSON is indented, this could work:

Regex.Replace(result, @"(\s*)""@(.*)"":", @"$1""$2"":", RegexOptions.IgnoreCase);


First replace all "@" in your xml content with some placeholder (as example {{at_the_rate}}). Then use below code

JsonConvert.SerializeXmlNode(doc).Replace("@", "").Replace("{{at_the_rate}}", "@")
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜