Zacząłem używać Json.NET do konwersji łańcucha w formacie JSON na obiekt lub odwrotnie. Nie jestem pewien w środowisku Json.NET, czy można przekonwertować ciąg znaków w formacie JSON na format XML i odwrotnie?
Zacząłem używać Json.NET do konwersji łańcucha w formacie JSON na obiekt lub odwrotnie. Nie jestem pewien w środowisku Json.NET, czy można przekonwertować ciąg znaków w formacie JSON na format XML i odwrotnie?
Odpowiedzi:
Tak. Korzystanie z klasy JsonConvert, która zawiera metody pomocnicze do tego właśnie celu:
// To convert an XML node contained in string xml into a JSON string
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
// To convert JSON text contained in string json into an XML node
XmlDocument doc = JsonConvert.DeserializeXmlNode(json);
Dokumentacja tutaj: Konwersja między JSON i XML za pomocą Json.NET
Tak, możesz to zrobić (ja to robię), ale miej na uwadze pewne paradoksy podczas konwersji i odpowiednio się z nimi obchodź. Nie można automatycznie dostosować się do wszystkich możliwości interfejsu, a kontrolowanie konwersji ma ograniczoną wbudowaną obsługę - wiele struktur JSON i wartości nie może być automatycznie konwertowanych w obie strony. Pamiętaj, że korzystam z ustawień domyślnych z biblioteką Newtonsoft JSON i biblioteką MS XML, więc twój przebieg może się różnić:
{}
LUB zagnieżdżonymi tablicami, w [ {} {} ...]
zależności od tego, czy jest tylko jeden, czy więcej niż jeden element potomny XML. Zużyłbyś je w różny sposób w JavaScript itp. Różne przykłady XML zgodnego z tym samym schematem mogą w ten sposób wytwarzać różne struktury JSON. Możesz dodać atrybut json: Array = 'true' do swojego elementu, aby obejść to w niektórych (ale niekoniecznie wszystkich) przypadkach.Nowa aktualizacja to zmienia (dzięki Jon Story za zwrócenie na to uwagi): https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm
Możesz wspomnieć o wszelkich innych zauważonych problemach. Opracowałem własne niestandardowe procedury przygotowywania i czyszczenia ciągów podczas konwersji w tę iz powrotem. Twoja sytuacja może, ale nie musi wymagać przygotowania / czyszczenia. Jak wspomina StaxMan, twoja sytuacja może wymagać konwersji między obiektami ... może to pociągać za sobą odpowiednie interfejsy i kilka instrukcji case / etc do obsługi ostrzeżeń, o których wspomniałem powyżej.
Możesz wykonać te konwersje również w .NET Framework:
JSON na XML: przy użyciu System.Runtime.Serialization.Json
var xml = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(
Encoding.ASCII.GetBytes(jsonString), new XmlDictionaryReaderQuotas()));
XML do JSON: przy użyciu System.Web.Script.Serialization
var json = new JavaScriptSerializer().Serialize(GetXmlData(XElement.Parse(xmlString)));
private static Dictionary<string, object> GetXmlData(XElement xml)
{
var attr = xml.Attributes().ToDictionary(d => d.Name.LocalName, d => (object)d.Value);
if (xml.HasElements) attr.Add("_value", xml.Elements().Select(e => GetXmlData(e)));
else if (!xml.IsEmpty) attr.Add("_value", xml.Value);
return new Dictionary<string, object> { { xml.Name.LocalName, attr } };
}
Nie jestem pewien, czy taka konwersja ma sens (tak, wielu to robi, ale głównie, aby przeforsować kwadratowy kołek przez okrągły otwór) - występuje niedopasowanie impedancji strukturalnej, a konwersja jest stratna. Odradzam więc takie transformacje między formatami.
Ale jeśli to zrobisz, najpierw przekonwertuj z json na obiekt, a następnie z obiektu na xml (i odwrotnie dla odwrotnego kierunku). Wykonanie bezpośredniej transformacji prowadzi do brzydkich wyników, utraty informacji lub być może obu naraz.
Dzięki dla Davida Browna odpowiedź . W moim przypadku JSON.Net 3.5 metody konwersji znajdują się w klasie statycznej JsonConvert:
XmlNode myXmlNode = JsonConvert.DeserializeXmlNode(myJsonString); // is node not note
// or .DeserilizeXmlNode(myJsonString, "root"); // if myJsonString does not have a root
string jsonString = JsonConvert.SerializeXmlNode(myXmlNode);
Długo szukałem alternatywnego kodu do zaakceptowanego rozwiązania w nadziei, że nie użyję zewnętrznego zespołu / projektu. Wymyśliłem następujące dzięki kodowi źródłowemu projektu DynamicJson :
public XmlDocument JsonToXML(string json)
{
XmlDocument doc = new XmlDocument();
using (var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(json), XmlDictionaryReaderQuotas.Max))
{
XElement xml = XElement.Load(reader);
doc.LoadXml(xml.ToString());
}
return doc;
}
Uwaga: Chciałem XmlDocument zamiast XElement dla celów xPath. Ponadto, ten kod oczywiście przechodzi tylko z JSON na XML, istnieją różne sposoby, aby zrobić odwrotnie.
Oto pełny kod c # do konwersji xml do json
public static class JSon
{
public static string XmlToJSON(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
return XmlToJSON(doc);
}
public static string XmlToJSON(XmlDocument xmlDoc)
{
StringBuilder sbJSON = new StringBuilder();
sbJSON.Append("{ ");
XmlToJSONnode(sbJSON, xmlDoc.DocumentElement, true);
sbJSON.Append("}");
return sbJSON.ToString();
}
// XmlToJSONnode: Output an XmlElement, possibly as part of a higher array
private static void XmlToJSONnode(StringBuilder sbJSON, XmlElement node, bool showNodeName)
{
if (showNodeName)
sbJSON.Append("\"" + SafeJSON(node.Name) + "\": ");
sbJSON.Append("{");
// Build a sorted list of key-value pairs
// where key is case-sensitive nodeName
// value is an ArrayList of string or XmlElement
// so that we know whether the nodeName is an array or not.
SortedList<string, object> childNodeNames = new SortedList<string, object>();
// Add in all node attributes
if (node.Attributes != null)
foreach (XmlAttribute attr in node.Attributes)
StoreChildNode(childNodeNames, attr.Name, attr.InnerText);
// Add in all nodes
foreach (XmlNode cnode in node.ChildNodes)
{
if (cnode is XmlText)
StoreChildNode(childNodeNames, "value", cnode.InnerText);
else if (cnode is XmlElement)
StoreChildNode(childNodeNames, cnode.Name, cnode);
}
// Now output all stored info
foreach (string childname in childNodeNames.Keys)
{
List<object> alChild = (List<object>)childNodeNames[childname];
if (alChild.Count == 1)
OutputNode(childname, alChild[0], sbJSON, true);
else
{
sbJSON.Append(" \"" + SafeJSON(childname) + "\": [ ");
foreach (object Child in alChild)
OutputNode(childname, Child, sbJSON, false);
sbJSON.Remove(sbJSON.Length - 2, 2);
sbJSON.Append(" ], ");
}
}
sbJSON.Remove(sbJSON.Length - 2, 2);
sbJSON.Append(" }");
}
// StoreChildNode: Store data associated with each nodeName
// so that we know whether the nodeName is an array or not.
private static void StoreChildNode(SortedList<string, object> childNodeNames, string nodeName, object nodeValue)
{
// Pre-process contraction of XmlElement-s
if (nodeValue is XmlElement)
{
// Convert <aa></aa> into "aa":null
// <aa>xx</aa> into "aa":"xx"
XmlNode cnode = (XmlNode)nodeValue;
if (cnode.Attributes.Count == 0)
{
XmlNodeList children = cnode.ChildNodes;
if (children.Count == 0)
nodeValue = null;
else if (children.Count == 1 && (children[0] is XmlText))
nodeValue = ((XmlText)(children[0])).InnerText;
}
}
// Add nodeValue to ArrayList associated with each nodeName
// If nodeName doesn't exist then add it
List<object> ValuesAL;
if (childNodeNames.ContainsKey(nodeName))
{
ValuesAL = (List<object>)childNodeNames[nodeName];
}
else
{
ValuesAL = new List<object>();
childNodeNames[nodeName] = ValuesAL;
}
ValuesAL.Add(nodeValue);
}
private static void OutputNode(string childname, object alChild, StringBuilder sbJSON, bool showNodeName)
{
if (alChild == null)
{
if (showNodeName)
sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
sbJSON.Append("null");
}
else if (alChild is string)
{
if (showNodeName)
sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
string sChild = (string)alChild;
sChild = sChild.Trim();
sbJSON.Append("\"" + SafeJSON(sChild) + "\"");
}
else
XmlToJSONnode(sbJSON, (XmlElement)alChild, showNodeName);
sbJSON.Append(", ");
}
// Make a string safe for JSON
private static string SafeJSON(string sIn)
{
StringBuilder sbOut = new StringBuilder(sIn.Length);
foreach (char ch in sIn)
{
if (Char.IsControl(ch) || ch == '\'')
{
int ich = (int)ch;
sbOut.Append(@"\u" + ich.ToString("x4"));
continue;
}
else if (ch == '\"' || ch == '\\' || ch == '/')
{
sbOut.Append('\\');
}
sbOut.Append(ch);
}
return sbOut.ToString();
}
}
Aby przekonwertować dany ciąg XML na JSON, wystarczy wywołać funkcję XmlToJSON () jak poniżej.
string xml = "<menu id=\"file\" value=\"File\"> " +
"<popup>" +
"<menuitem value=\"New\" onclick=\"CreateNewDoc()\" />" +
"<menuitem value=\"Open\" onclick=\"OpenDoc()\" />" +
"<menuitem value=\"Close\" onclick=\"CloseDoc()\" />" +
"</popup>" +
"</menu>";
string json = JSON.XmlToJSON(xml);
// json = { "menu": {"id": "file", "popup": { "menuitem": [ {"onclick": "CreateNewDoc()", "value": "New" }, {"onclick": "OpenDoc()", "value": "Open" }, {"onclick": "CloseDoc()", "value": "Close" } ] }, "value": "File" }}
Wypróbuj tę funkcję. Właśnie to napisałem i nie miałem wiele okazji do przetestowania, ale moje wstępne testy są obiecujące.
public static XmlDocument JsonToXml(string json)
{
XmlNode newNode = null;
XmlNode appendToNode = null;
XmlDocument returnXmlDoc = new XmlDocument();
returnXmlDoc.LoadXml("<Document />");
XmlNode rootNode = returnXmlDoc.SelectSingleNode("Document");
appendToNode = rootNode;
string[] arrElementData;
string[] arrElements = json.Split('\r');
foreach (string element in arrElements)
{
string processElement = element.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim();
if ((processElement.IndexOf("}") > -1 || processElement.IndexOf("]") > -1) && appendToNode != rootNode)
{
appendToNode = appendToNode.ParentNode;
}
else if (processElement.IndexOf("[") > -1)
{
processElement = processElement.Replace(":", "").Replace("[", "").Replace("\"", "").Trim();
newNode = returnXmlDoc.CreateElement(processElement);
appendToNode.AppendChild(newNode);
appendToNode = newNode;
}
else if (processElement.IndexOf("{") > -1 && processElement.IndexOf(":") > -1)
{
processElement = processElement.Replace(":", "").Replace("{", "").Replace("\"", "").Trim();
newNode = returnXmlDoc.CreateElement(processElement);
appendToNode.AppendChild(newNode);
appendToNode = newNode;
}
else
{
if (processElement.IndexOf(":") > -1)
{
arrElementData = processElement.Replace(": \"", ":").Replace("\",", "").Replace("\"", "").Split(':');
newNode = returnXmlDoc.CreateElement(arrElementData[0]);
for (int i = 1; i < arrElementData.Length; i++)
{
newNode.InnerText += arrElementData[i];
}
appendToNode.AppendChild(newNode);
}
}
}
return returnXmlDoc;
}
Oto prosty fragment kodu, który konwertuje XmlNode (rekurencyjnie) na tablicę mieszającą i grupuje wiele instancji tego samego dziecka w tablicy (jako ArrayList). Hashtable jest zwykle akceptowany do konwersji na JSON przez większość bibliotek JSON.
protected object convert(XmlNode root){
Hashtable obj = new Hashtable();
for(int i=0,n=root.ChildNodes.Count;i<n;i++){
object result = null;
XmlNode current = root.ChildNodes.Item(i);
if(current.NodeType != XmlNodeType.Text)
result = convert(current);
else{
int resultInt;
double resultFloat;
bool resultBoolean;
if(Int32.TryParse(current.Value, out resultInt)) return resultInt;
if(Double.TryParse(current.Value, out resultFloat)) return resultFloat;
if(Boolean.TryParse(current.Value, out resultBoolean)) return resultBoolean;
return current.Value;
}
if(obj[current.Name] == null)
obj[current.Name] = result;
else if(obj[current.Name].GetType().Equals(typeof(ArrayList)))
((ArrayList)obj[current.Name]).Add(result);
else{
ArrayList collision = new ArrayList();
collision.Add(obj[current.Name]);
collision.Add(result);
obj[current.Name] = collision;
}
}
return obj;
}
Cinchoo ETL - biblioteka open source dostępna do łatwej konwersji Xml na JSON z kilkoma liniami kodu
Xml -> JSON:
using (var p = new ChoXmlReader("sample.xml"))
{
using (var w = new ChoJSONWriter("sample.json"))
{
w.Write(p);
}
}
JSON -> Xml:
using (var p = new ChoJsonReader("sample.json"))
{
using (var w = new ChoXmlWriter("sample.xml"))
{
w.Write(p);
}
}
Zapoznaj się z artykułem CodeProject, aby uzyskać dodatkową pomoc.
Oświadczenie: Jestem autorem tej biblioteki.
Tak jak powiedział David Brown, ale dostałem następujący wyjątek.
$exception {"There are multiple root elements. Line , position ."} System.Xml.XmlException
Jednym rozwiązaniem byłoby zmodyfikowanie pliku XML za pomocą elementu głównego, ale nie zawsze jest to konieczne, a dla strumienia XML może to również nie być możliwe. Moje rozwiązanie poniżej:
var path = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\App_Data"));
var directoryInfo = new DirectoryInfo(path);
var fileInfos = directoryInfo.GetFiles("*.xml");
foreach (var fileInfo in fileInfos)
{
XmlDocument doc = new XmlDocument();
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlReader reader = XmlReader.Create(fileInfo.FullName, settings))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
var node = doc.ReadNode(reader);
string json = JsonConvert.SerializeXmlNode(node);
}
}
}
}
Przykładowy XML, który generuje błąd:
<parent>
<child>
Text
</child>
</parent>
<parent>
<child>
<grandchild>
Text
</grandchild>
<grandchild>
Text
</grandchild>
</child>
<child>
Text
</child>
</parent>
Użyłem poniższych metod do konwersji JSON na XML
List <Item> items;
public void LoadJsonAndReadToXML() {
using(StreamReader r = new StreamReader(@ "E:\Json\overiddenhotelranks.json")) {
string json = r.ReadToEnd();
items = JsonConvert.DeserializeObject <List<Item>> (json);
ReadToXML();
}
}
I
public void ReadToXML() {
try {
var xEle = new XElement("Items",
from item in items select new XElement("Item",
new XElement("mhid", item.mhid),
new XElement("hotelName", item.hotelName),
new XElement("destination", item.destination),
new XElement("destinationID", item.destinationID),
new XElement("rank", item.rank),
new XElement("toDisplayOnFod", item.toDisplayOnFod),
new XElement("comment", item.comment),
new XElement("Destinationcode", item.Destinationcode),
new XElement("LoadDate", item.LoadDate)
));
xEle.Save("E:\\employees.xml");
Console.WriteLine("Converted to XML");
} catch (Exception ex) {
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
Użyłem klasy o nazwie Przedmiot do przedstawienia elementów
public class Item {
public int mhid { get; set; }
public string hotelName { get; set; }
public string destination { get; set; }
public int destinationID { get; set; }
public int rank { get; set; }
public int toDisplayOnFod { get; set; }
public string comment { get; set; }
public string Destinationcode { get; set; }
public string LoadDate { get; set; }
}
To działa....
Aby przekonwertować JSON
ciąg, XML
spróbuj tego:
public string JsonToXML(string json)
{
XDocument xmlDoc = new XDocument(new XDeclaration("1.0", "utf-8", ""));
XElement root = new XElement("Root");
root.Name = "Result";
var dataTable = JsonConvert.DeserializeObject<DataTable>(json);
root.Add(
from row in dataTable.AsEnumerable()
select new XElement("Record",
from column in dataTable.Columns.Cast<DataColumn>()
select new XElement(column.ColumnName, row[column])
)
);
xmlDoc.Add(root);
return xmlDoc.ToString();
}
Do konwersji XML
do JSON
spróbuj tego:
public string XmlToJson(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
return jsonText;
}
użyj biblioteki innej firmy, zamiast pisać własny kod do parsowania JSON lub XML String. Jeśli jest to jednorazowe użycie, spróbuj przekonwertować go online. Json do Xml https://www.easycodeforall.com/Json2Xml.jsp Xml do Json https://www.easycodeforall.com/Xml2Json.jsp