Я собираюсь загрузить большое количество XML-файлов InfoPath в Cosmos DB в виде файлов Json для тестирования возможного проекта. Но мне трудно преобразовать файлы XML в Json, а затем загрузить обратно в класс C#. Я думаю, что это связано с пространством имен, которое InfoPath помещает в XML, но я не уверен. Сначала я подумал, что мне нужно попытаться удалить все ссылки на пространства имен из XML, но теперь мне интересно, нужно ли мне просто больше поработать над определением файла класса. Для создания файла класса я использовал Visual Studio «вставить как Json». Я предположил, что после загрузки XML, сохранения в Json, а затем использования этого в качестве основы для нового файла класса я могу загрузить его обратно в объект, но когда я вызываю DeserializeObject, он всегда заканчивается нулевым.
Это потому, что необходимо изменить определение файла класса, или мне лучше попытаться очистить XML перед преобразованием в Json?
Образец XML
<?xml version = "1.0" encoding = "utf-8"?>
<?mso-infoPathSolution name = "urn:schemas-microsoft-com:office:infopath:myProject:-myXSD-2017-05-05T14-19-13" solutionVersion = "1.0.0.2046" productVersion = "16.0.0.0" PIVersion = "1.0.0.0" href = "https://myportal.sharepoint.com/sites/mySite/myProject/Forms/template.xsn"?>
<?mso-application progid = "InfoPath.Document" versionProgid = "InfoPath.Document.4"?>
<?mso-infoPath-file-attachment-present?>
<my:myFields xmlns:my = "http://schemas.microsoft.com/office/infopath/2003/myXSD/2017-05-05T14:19:13" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml = "http://www.w3.org/1999/xhtml" xmlns:pc = "http://schemas.microsoft.com/office/infopath/2007/PartnerControls" xmlns:ma = "http://schemas.microsoft.com/office/2009/metadata/properties/metaAttributes" xmlns:d = "http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields" xmlns:q = "http://schemas.microsoft.com/office/infopath/2009/WSSList/queryFields" xmlns:dfs = "http://schemas.microsoft.com/office/infopath/2003/dataFormSolution" xmlns:dms = "http://schemas.microsoft.com/office/2009/documentManagement/types" xmlns:tns = "http://microsoft.com/webservices/SharePointPortalServer/UserProfileService" xmlns:s1 = "http://microsoft.com/wsdl/types/" xmlns:http = "http://schemas.xmlsoap.org/wsdl/http/" xmlns:tm = "http://microsoft.com/wsdl/mime/textMatching/" xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc = "http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime = "http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap12 = "http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsdl = "http://schemas.xmlsoap.org/wsdl/" xmlns:xd = "http://schemas.microsoft.com/office/infopath/2003" xml:lang = "en-US">
<my:Admin>
<my:Routing_Order>
<my:Approver-1_Order>1</my:Approver-1_Order>
<my:Approver-2_Order>5</my:Approver-2_Order>
<my:Approver-3_Order>4</my:Approver-3_Order>
</my:Routing_Order>
</my:Admin>
<my:Request_Status>Save as Draft</my:Request_Status>
<my:Request_Type>CAPEX</my:Request_Type>
</my:myFields>
Файл класса
namespace xml_to_json
{
public class Rootobject
{
public MyMyfields mymyFields { get; set; }
}
public class MyMyfields
{
public string xmlnsmy { get; set; }
public string xmlnsxsi { get; set; }
public string xmlnsxhtml { get; set; }
public string xmlnspc { get; set; }
public string xmlnsma { get; set; }
public string xmlnsd { get; set; }
public string xmlnsq { get; set; }
public string xmlnsdfs { get; set; }
public string xmlnsdms { get; set; }
public string xmlnstns { get; set; }
public string xmlnss1 { get; set; }
public string xmlnshttp { get; set; }
public string xmlnstm { get; set; }
public string xmlnssoap { get; set; }
public string xmlnssoapenc { get; set; }
public string xmlnsmime { get; set; }
public string xmlnssoap12 { get; set; }
public string xmlnswsdl { get; set; }
public string xmlnsxd { get; set; }
public string xmllang { get; set; }
public MyAdmin myAdmin { get; set; }
public string myRequest_Status { get; set; }
public string myRequest_Type { get; set; }
}
public class MyAdmin
{
public MyRouting_Order myRouting_Order { get; set; }
}
public class MyRouting_Order
{
public string myApprover1_Order { get; set; }
public string myApprover2_Order { get; set; }
public string myApprover3_Order { get; set; }
}
}
Код теста консоли
namespace xml_to_json
{
class Program
{
static void Main(string[] args)
{
XmlDocument myDoc = new XmlDocument();
string sourcedir = @"C:\Users\mystuff\Downloads\test-clean\";
string xmlfilein = @"test";
string xmlfile = string.Concat(sourcedir, xmlfilein, ".xml");
string jsonfileout = string.Concat(sourcedir, xmlfilein, ".json");
myDoc.Load(xmlfile);
string jsonText = JsonConvert.SerializeXmlNode(myDoc.LastChild);
File.WriteAllText(jsonfileout, jsonText);
Rootobject obj = new Rootobject();
obj = JsonConvert.DeserializeObject<Rootobject>(jsonText);
Console.WriteLine(obj.mymyFields.myRequest_Status);
}
}
}
Если я правильно понимаю вашу идею, цель состоит не в том, чтобы поместить XML-данные в объект. Цель состоит в том, чтобы преобразовать данные XML в формат Json, чтобы их можно было загрузить в Cosmos DB, а затем протестировать, используя этот документ Json в качестве объекта. Преобразование в Json - это не шаг, который я хочу пропустить, а часть процесса, которому мне нужно следовать.
Хорошо, тогда зачем тебе Rootobject
? После того, как у вас есть jsonText
, вы преобразовали свои XML-данные в формат JSON и все готово, верно?
RootObject был создан из команды вставки в Json, о которой я упоминал в моем первом посте. Я надеялся, что Visual Studio сможет сделать перевод за меня. Наличие файла Json - это часть шага. Я мог бы загрузить Cosmos DB. Однако следующим моим шагом будет чтение этого файла и загрузка его в объект, чтобы я мог протестировать создание пользовательского интерфейса для этих документов. Чем больше я исследую, тем больше я думаю, что мне нужно удалить пространства имен и другие директивы в XML, прежде чем я попытаюсь выполнить преобразование.
Попробуйте код ниже, используя xml linq:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement routingOrder = doc.Descendants().Where(x => x.Name.LocalName == "Routing_Order").FirstOrDefault();
Dictionary<string, string> orders = routingOrder.Elements()
.GroupBy(x => x.Name.LocalName, y => (string)y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
string status = (string)doc.Descendants().Where(x => x.Name.LocalName == "Request_Status").FirstOrDefault();
string requestType = (string)doc.Descendants().Where(x => x.Name.LocalName == "Request_Type").FirstOrDefault();
}
}
}
Я думаю, что мог бы сделать то же самое с XMLDocument и сопоставить путь к каждому узлу, но я больше искал способ заставить DeserializeObject работать без сопоставления каждого узла по отдельности. Возможно, я отредактирую исходный вопрос, чтобы больше сосредоточиться на том, как определить объект Json, когда задействовано пространство имен.
Попробуйте сериализовать в файл, а затем десериализовать файл. Это покажет, верны ли определения классов. Тогда вы узнаете, в чем проблема: в классах или в json.
Использование предложения от jdweng и XDocument помогло очистить файл XML для облегчения перехода на Json. Ниже приведен пример кода, который я использовал для очистки документа.
XDocument newxdoc = XDocument.Load(xmlfile);
newxdoc.DescendantNodes().Where(e => e.NodeType.ToString().StartsWith("ProcessingInstruction")).Remove();
string newstringdoc = RemoveAllNamespaces(newxdoc.ToString());
newxdoc = XDocument.Parse(newstringdoc);
Почему бы не выполнить десериализацию напрямую с помощью
XmlSerializer
? Если вы используетеXmlSerializer
, вы можете полностью пропустить промежуточное представление JSON.