แปลงสตริง XML เป็นวัตถุ


180

ฉันได้รับสตริง XML ผ่านซ็อกเก็ตและต้องการแปลงเป็นวัตถุ C #

ข้อความมีรูปแบบ:

<msg>
   <id>1</id>
   <action>stop</action>
</msg>

ฉันใหม่กับ. Net และไม่แน่ใจว่าวิธีปฏิบัติที่ดีที่สุดสำหรับการดำเนินการนี้ ฉันเคยใช้ JAXB สำหรับ Java มาก่อนและไม่แน่ใจว่ามีอะไรที่คล้ายกันหรือว่าจะจัดการในลักษณะที่แตกต่างออกไป


3
คุณมีวัตถุเหล่านี้กลายเป็นหรือคุณต้องการที่จะสร้างวัตถุแบบไดนามิก?
เตฟาน


สำหรับฉันนี่เป็นตัวเลือกที่ดีที่สุด: stackoverflow.com/a/24184283/2647430
Ivan Lopez

คำตอบ:


277

คุณต้องใช้xsd.exeเครื่องมือที่ได้รับการติดตั้งด้วย Windows SDK ในไดเรกทอรีสิ่งที่คล้ายกับ:

C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin

และในคอมพิวเตอร์ 64 บิต:

C:\Program Files (x86)\Microsoft SDKs\Windows\v6.0A\bin

และบนคอมพิวเตอร์ Windows 10:

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin

ในการรันครั้งแรกคุณใช้xsd.exeและคุณแปลง XML ตัวอย่างของคุณเป็นไฟล์ XSD (ไฟล์ XML schema):

xsd yourfile.xml

สิ่งนี้ให้คุณyourfile.xsdซึ่งในขั้นตอนที่สองคุณสามารถแปลงอีกครั้งโดยใช้xsd.exeเป็นคลาส C #:

xsd yourfile.xsd /c

สิ่งนี้จะให้ไฟล์yourfile.csซึ่งจะมีคลาส C # ที่คุณสามารถใช้ในการ deserialize ไฟล์ XML ที่คุณได้รับ - เช่น:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
msg resultingMessage = (msg)serializer.Deserialize(new XmlTextReader("yourfile.xml"));

ควรทำงานค่อนข้างดีสำหรับกรณีส่วนใหญ่

อัปเดต: XML serializer จะใช้สตรีมใด ๆ ก็ได้เป็นอินพุต - ไฟล์หรือสตรีมหน่วยความจำจะใช้ได้:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(inputString));
msg resultingMessage = (msg)serializer.Deserialize(memStream);

หรือใช้ StringReader:

XmlSerializer serializer = new XmlSerializer(typeof(msg));
StringReader rdr = new StringReader(inputString);
msg resultingMessage = (msg)serializer.Deserialize(rdr);

ขอบคุณสำหรับคำอธิบายโดยละเอียด ในกรณีของฉัน XML จะมาเหนือซ็อกเก็ตและเป็นสตริง ฉันจะยกเลิกการทำให้เป็นสตริงสตริงแทนไฟล์ XML ได้อย่างไร
Steve

5
@Steve: คุณสามารถเปิด StringReader และผ่าน Deserialize method StringReader มาจาก TextReader
Skurmedel

คุณต้องการที่จะเข้าใกล้คนที่ Fahad พูดถึงโดยใช้ Linq หรือไม่?
Steve

2
@ Steve: ใช่ฉันต้องการ - deserializing เป็นวัตถุและความสามารถในการโผล่ที่คุณสมบัติของวัตถุดูเหมือนจะง่ายกว่าการทำ wiggling ด้วยองค์ประกอบ XML คุณลักษณะโหนดลูกเป็นต้น Linq-to-XML นั้นยอดเยี่ยมถ้า XML ผิดปกติและเปลี่ยนแปลงตลอดเวลาหรือไม่ทราบล่วงหน้า
marc_s

7
เว็บไซต์นี้ง่ายกว่าเครื่องมือ xsd IMO: xmltocsharp.azurewebsites.net
nasch

227

คุณมีความเป็นไปได้สองอย่าง

วิธีที่ 1 เครื่องมือXSD


สมมติว่าคุณมีไฟล์ XML ในตำแหน่งนี้ C:\path\to\xml\file.xml

  1. เปิดพรอมต์คำสั่งสำหรับนักพัฒนา
    คุณสามารถค้นหาได้ในStart Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools หรือถ้าคุณมี Windows 8 สามารถเริ่มพิมพ์พรอมต์คำสั่งสำหรับนักพัฒนาได้ในหน้าจอเริ่ม
  2. เปลี่ยนตำแหน่งไปยังไดเรกทอรีไฟล์ XML ของคุณโดยพิมพ์ cd /D "C:\path\to\xml"
  3. สร้างไฟล์ XSDจากไฟล์ xml ของคุณโดยพิมพ์xsd file.xml
  4. สร้างคลาส C #โดยพิมพ์xsd /c file.xsd

และนั่นมัน! คุณได้สร้างคลาส C # จากไฟล์ xml ในC:\path\to\xml\file.cs

วิธีที่ 2 - วางแบบพิเศษ


Visual Studio 2012+ ที่จำเป็นต้องมี. Net Framework> = 4.5 เป็นเป้าหมายของโครงการและติดตั้งคอมโพเนนต์เฉพาะ 'Windows Communication Foundation'

  1. คัดลอกเนื้อหาของไฟล์ XML ของคุณไปยังคลิปบอร์ด
  2. เพิ่มในโซลูชันของคุณไฟล์คลาสใหม่ที่ว่างเปล่า ( Shift+ Alt+ C)
  3. เปิดไฟล์นั้นและคลิกที่เมนู Edit > Paste special > Paste XML As Classes
    ป้อนคำอธิบายรูปภาพที่นี่

และนั่นมัน!

การใช้


การใช้งานง่ายมากกับคลาสตัวช่วยนี้:

using System;
using System.IO;
using System.Web.Script.Serialization; // Add reference: System.Web.Extensions
using System.Xml;
using System.Xml.Serialization;

namespace Helpers
{
    internal static class ParseHelpers
    {
        private static JavaScriptSerializer json;
        private static JavaScriptSerializer JSON { get { return json ?? (json = new JavaScriptSerializer()); } }

        public static Stream ToStream(this string @this)
        {
            var stream = new MemoryStream();
            var writer = new StreamWriter(stream);
            writer.Write(@this);
            writer.Flush();
            stream.Position = 0;
            return stream;
        }


        public static T ParseXML<T>(this string @this) where T : class
        {
            var reader = XmlReader.Create(@this.Trim().ToStream(), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Document });
            return new XmlSerializer(typeof(T)).Deserialize(reader) as T;
        }

        public static T ParseJSON<T>(this string @this) where T : class
        {
            return JSON.Deserialize<T>(@this.Trim());
        }
    }
}

สิ่งที่คุณต้องทำตอนนี้คือ:

    public class JSONRoot
    {
        public catalog catalog { get; set; }
    }
    // ...

    string xml = File.ReadAllText(@"D:\file.xml");
    var catalog1 = xml.ParseXML<catalog>();

    string json = File.ReadAllText(@"D:\file.json");
    var catalog2 = json.ParseJSON<JSONRoot>();

7
ไชโย Re: วิธีที่ 2 คุณต้องกำหนดเป้าหมายเป็น. net 4.5 หากไม่มีตัวเลือก
timB33

12
วิธีที่ 2 มีประโยชน์อย่างน่าขัน! ขอบคุณสำหรับสิ่งนั้น ฉันไม่รู้ว่ามีอยู่จริง
Dominic Bindley

1
รุ่งโรจน์สำหรับวิธีที่ 2 ทำงานเหมือนมีเสน่ห์ ยอดเยี่ยมเมื่อพยายามแยกวิเคราะห์ XML แบบเป็นโปรแกรมโดยไม่ต้องใช้คลาสที่น่าเบื่อ
อเล็กซ์

1
คุณควรทำให้ "วางแบบพิเศษ" เป็นวิธีแรกซึ่งเป็นวิธีที่ง่ายที่สุด ข้อ จำกัด ".Net Framework> = 4.5" ไม่สำคัญในปี 2017
Michael Freidgeim

2
"วาง XML เป็นคลาส" ต้องการเวิร์กโหลด WCF สำหรับ Visual Studio ที่ติดตั้ง
Lennart

50

ลองวิธีนี้เพื่อแปลง Xml เป็นวัตถุ มันถูกสร้างขึ้นมาเพื่อสิ่งที่คุณกำลังทำ:

protected T FromXml<T>(String xml)
{
    T returnedXmlClass = default(T);

    try
    {
        using (TextReader reader = new StringReader(xml))
        {
            try
            {
                returnedXmlClass = 
                    (T)new XmlSerializer(typeof(T)).Deserialize(reader);
            }
            catch (InvalidOperationException)
            {
                // String passed is not XML, simply return defaultXmlClass
            }
        }
    }
    catch (Exception ex)
    {
    }

    return returnedXmlClass ;        
}

เรียกมันว่าใช้รหัสนี้:

YourStrongTypedEntity entity = FromXml<YourStrongTypedEntity>(YourMsgString);

6
มีข้อผิดพลาดนี้ xmlns = ''> ไม่ได้คาดว่า "}, ความคิดใด ๆ .
Prashant

ปัญหาคือคุณต้องทำให้ชั้นเรียนของคุณเกิดขึ้นอย่างสมบูรณ์แบบล่วงหน้า บางทีฟังก์ชั่นที่ส่งออกคลาสเมื่อกำหนด XML หรือไม่? xsd.exe ถูก hit & miss (ส่วนใหญ่จะพลาดเรื่องที่ซับซ้อน) ...
Yumi Koizumi

1
โอ้พระเจ้าฉันใช้เวลาหลายชั่วโมงในการจัดการกับ. nets xml serializer และสิ่งนี้ใช้ได้ทันทีจากประตู
clark christopher

11

เพียงเรียกใช้ Visual Studio 2013 ของคุณในฐานะผู้ดูแลระบบ ... คัดลอกเนื้อหาของไฟล์ Xml ของคุณไปที่ Visual Studio 2013> แก้ไข> วางแบบพิเศษ> วาง Xml เป็นคลาส C # มันจะสร้างคลาส c # ของคุณตามเนื้อหาไฟล์ Xml ของคุณ


7

ในกรณีที่ทุกคนอาจพบว่ามีประโยชน์:

public static class XmlConvert
{
    public static string SerializeObject<T>(T dataObject)
    {
        if (dataObject == null)
        {
            return string.Empty;
        }
        try
        {
            using (StringWriter stringWriter = new System.IO.StringWriter())
            {
                var serializer = new XmlSerializer(typeof(T));
                serializer.Serialize(stringWriter, dataObject);
                return stringWriter.ToString();
            }
        }
        catch (Exception ex)
        {
            return string.Empty;
        }
    }

    public static T DeserializeObject<T>(string xml)
         where T : new()
    {
        if (string.IsNullOrEmpty(xml))
        {
            return new T();
        }
        try
        {
            using (var stringReader = new StringReader(xml))
            {
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(stringReader);
            }
        }
        catch (Exception ex)
        {
            return new T();
        }
    }
}

คุณสามารถโทรหาได้โดยใช้:

MyCustomObject myObject = new MyCustomObject();
string xmlString = XmlConvert.SerializeObject(myObject)
myObject = XmlConvert.DeserializeObject<MyCustomObject>(xmlString);

5

คุณสามารถสร้างคลาสได้ตามที่อธิบายไว้ข้างต้นหรือเขียนด้วยตนเอง:

[XmlRoot("msg")]
public class Message
{
    [XmlElement("id")]
    public string Id { get; set; }
    [XmlElement("action")]
    public string Action { get; set; }
}

จากนั้นคุณสามารถใช้ExtendedXmlSerializerเพื่อทำให้เป็นอนุกรมและดีซีเรียลไลซ์

การ ติดตั้งคุณสามารถติดตั้ง ExtendedXmlSerializer จากnugetหรือเรียกใช้คำสั่งต่อไปนี้:

Install-Package ExtendedXmlSerializer

อันดับ:

var serializer = new ConfigurationContainer().Create();
var obj = new Message();
var xml = serializer.Serialize(obj);

ซีเรียลไลซ์

var obj2 = serializer.Deserialize<Message>(xml);

การสนับสนุน serializer นี้:

  • Deserialization xml จาก XMLSerializer มาตรฐาน
  • คลาสการทำให้เป็นอนุกรม, คลาสคลาส, ชนิดดั้งเดิม, รายการทั่วไปและพจนานุกรม, อาร์เรย์, enum
  • คลาสการทำให้เป็นอนุกรมกับอินเตอร์เฟสคุณสมบัติ
  • หมายเลขอ้างอิงแบบวงกลมและหมายเลขอ้างอิง
  • การดีซีเรียลไลเซชันของ xml รุ่นเก่า
  • การเข้ารหัสคุณสมบัติ
  • Serializer ที่กำหนดเอง
  • สนับสนุน XmlElementAttribute และ XmlRootAttribute
  • POCO - การกำหนดค่าทั้งหมด (การย้ายข้อมูล, serializer ที่กำหนดเอง ... ) อยู่นอกชั้นเรียน

ExtendedXmlSerializer สนับสนุน.NET 4.5หรือสูงกว่าและ.NET หลัก คุณสามารถรวมเข้ากับ WebApi และ AspCore


1
โพสต์ที่ยอดเยี่ยม! ฉันอัปเดตโค้ดเพื่อทำให้ทันสมัยขึ้นตามเอกสารgithub.com/wojtpl2/ExtendedXmlSerializer
user1477388


2

ลดความซับซ้อนของคำตอบที่ดีของ Damian

public static T ParseXml<T>(this string value) where T : class
{
    var xmlSerializer = new XmlSerializer(typeof(T));
    using (var textReader = new StringReader(value))
    {
        return (T) xmlSerializer.Deserialize(textReader);
    }
}

1

สร้าง DTO เป็น CustomObject

ใช้วิธีการด้านล่างเพื่อแปลงสตริง XML เป็น DTO โดยใช้ JAXB

private static CustomObject getCustomObject(final String ruleStr) {
    CustomObject customObject = null;
    try {
        JAXBContext jaxbContext = JAXBContext.newInstance(CustomObject.class);
        final StringReader reader = new StringReader(ruleStr);
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        customObject = (CustomObject) jaxbUnmarshaller.unmarshal(reader);
    } catch (JAXBException e) {
        LOGGER.info("getCustomObject parse error: ", e);
    }
    return customObject;
}

0

หากคุณมี xsd ของข้อความ xml คุณสามารถสร้างคลาส c # โดยใช้เครื่องมือ. Net xsd.exe

คลาส. Net นี้สามารถใช้เพื่อสร้าง xml


0

นอกเหนือจากคำตอบอื่น ๆ ที่นี่คุณสามารถใช้คลาสXmlDocument , สำหรับการอ่าน XML DOM-like หรือXmlReader , ตัวอ่านไปข้างหน้าอย่างรวดเร็วเพื่อทำ "ด้วยมือ"


0

อีกวิธีหนึ่งด้วยเครื่องมือสร้างรุ่น xsd ถึง c # ระดับสูง: xsd2code.com เครื่องมือนี้มีประโยชน์มากและมีประสิทธิภาพ มีการกำหนดเองมากขึ้นกว่าเครื่องมือ xsd.exe จาก Visual Studio Xsd2Code ++ สามารถปรับแต่งให้ใช้รายการหรืออาร์เรย์และรองรับสคีมาขนาดใหญ่พร้อมคำสั่งการนำเข้าจำนวนมาก

หมายเหตุของคุณสมบัติบางอย่าง

  • สร้างวัตถุธุรกิจจากไฟล์ XSD Schema หรือ XML เป็นรหัส C # หรือ Visual Basic ที่มีความยืดหยุ่น
  • รองรับ Framework 2.0 ถึง 4.x
  • สนับสนุนคอลเลกชันที่พิมพ์ที่แข็งแกร่ง (รายการ ObservableCollection, MyCustomCollection)
  • รองรับคุณสมบัติอัตโนมัติ
  • สร้างวิธีการอ่านและเขียน XML (อนุกรม / deserialization)
  • รองรับ Databinding (WPF, Xamarin)
  • WCF (แอตทริบิวต์ DataMember)
  • รองรับการเข้ารหัส XML (UTF-8/32, ASCII, Unicode, Custom)
  • การสนับสนุน Camel case / Pascal Case
  • การสนับสนุนข้อ จำกัด ([StringLengthAttribute = true / false], [RegularExpressionAttribute = true / false], [RangeAttribute = true / false])
  • รองรับไฟล์ XSD ขนาดใหญ่และซับซ้อน
  • รองรับ DotNet Core และมาตรฐาน

0

ฉันรู้ว่าคำถามนี้เก่า แต่ฉันสะดุดลงและฉันมีคำตอบที่แตกต่างกันดีกว่าคนอื่น :-)

วิธีปกติ (ตามที่ผู้วิจารณ์กล่าวถึงข้างต้น) คือการสร้างคลาสและยกเลิกการทำให้เป็นอนุกรม xml ของคุณ

แต่ ( คำเตือน: การโปรโมตตนเองที่ไร้ยางอายที่นี่ ) ฉันเพิ่งเผยแพร่แพ็คเกจ nuget ที่นี่ซึ่งคุณไม่ต้องทำ คุณเพิ่งไป:

string xml = System.IO.File.ReadAllText(@"C:\test\books.xml");
var book = Dandraka.XmlUtilities.XmlSlurper.ParseText(xml);

นั่นคือตัวอักษรมันไม่มีอะไรต้องการ และที่สำคัญที่สุดหาก xml ของคุณเปลี่ยนวัตถุของคุณก็จะเปลี่ยนโดยอัตโนมัติเช่นกัน

หากคุณต้องการดาวน์โหลด dll โดยตรง, หน้า GitHub เป็นที่นี่


-7
public string Serialize<T>(T settings)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    StringWriter outStream = new StringWriter();
    serializer.Serialize(outStream, settings);
    return outStream.ToString();
}

5
นี่คือวิธีการทำให้เป็นอันดับไม่ใช่วิธีเลิกซีเรียลไลซ์
alexc95

1
คุณเพิ่งเขียนรหัสที่นี่ มันไม่มีความหมายสำหรับคนส่วนใหญ่
M. Haché

โค้ดไม่ได้ทิ้งสายน้ำ
บิ๊กฟุต
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.