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}}", "@")
精彩评论