วิธีการจัดลำดับวัตถุเป็น XML โดยไม่ได้รับ xmlns =“ …”?


109

มีวิธีที่ฉันจะทำให้วัตถุเป็นอนุกรมใน. NET โดยไม่ต้องใช้เนมสเปซ XML โดยอัตโนมัติด้วยหรือไม่ ดูเหมือนว่าโดยค่าเริ่มต้น. NET เชื่อว่าควรรวมเนมสเปซ XSI และ XSD ไว้ด้วย แต่ฉันไม่ต้องการให้มี

คำตอบ:


142

อ่า ... ไม่เป็นไร มันมักจะเป็นการค้นหาหลังจากตั้งคำถามแล้วซึ่งให้คำตอบ อ็อบเจ็กต์ของฉันที่ถูกทำให้เป็นอนุกรมเป็นobjและถูกกำหนดไว้แล้ว การเพิ่ม XMLSerializerNamespace ด้วยเนมสเปซว่างเดียวในคอลเลกชันจะเป็นเคล็ดลับ

ใน VB เช่นนี้:

Dim xs As New XmlSerializer(GetType(cEmploymentDetail))
Dim ns As New XmlSerializerNamespaces()
ns.Add("", "")

Dim settings As New XmlWriterSettings()
settings.OmitXmlDeclaration = True

Using ms As New MemoryStream(), _
    sw As XmlWriter = XmlWriter.Create(ms, settings), _
    sr As New StreamReader(ms)
xs.Serialize(sw, obj, ns)
ms.Position = 0
Console.WriteLine(sr.ReadToEnd())
End Using

ใน C # เช่นนี้:

//Create our own namespaces for the output
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

//Add an empty namespace and empty value
ns.Add("", "");

//Create the serializer
XmlSerializer slz = new XmlSerializer(someType);

//Serialize the object with our own namespaces (notice the overload)
slz.Serialize(myXmlTextWriter, someObject, ns);

12
ฉันลองสิ่งนี้ใน VB แอตทริบิวต์ xsi และ xsd หายไป แต่แอตทริบิวต์เช่น xmlns: q12 =, d3p1: type และ xmlns: d3p1 ปรากฏขึ้น
MiddleKay

16
ฉันลองใช้เวอร์ชัน C # และลบ xsi และ xsd ออก แต่เพิ่มคำนำหน้า q1: ให้กับชื่อแท็ก XML ทั้งหมดซึ่งฉันไม่ต้องการ ดูเหมือนว่าตัวอย่าง C # จะไม่สมบูรณ์โดยอ้างถึง myXmlTextWriter ซึ่งฉันคิดว่าต้องเริ่มต้นด้วยวิธีเดียวกับตัวอย่าง VB
redtetrahedron

1
@redtetrahedron คุณพบวิธีกำจัดq1อึหรือไม่?
ขยี้

อ้างถึงคำตอบstackoverflow.com/questions/31946240/…ถ้า q1 เพิ่มเป็นเนมสเปซว่าง
aniruddha

20

หากคุณต้องการกำจัดส่วนพิเศษxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"และxmlns:xsd="http://www.w3.org/2001/XMLSchema"แต่ยังคงเก็บเนมสเปซของคุณเองxmlns="http://schemas.YourCompany.com/YourSchema/"ไว้คุณใช้รหัสเดียวกับด้านบนยกเว้นการเปลี่ยนแปลงง่ายๆนี้:

//  Add lib namespace with empty prefix  
ns.Add("", "http://schemas.YourCompany.com/YourSchema/");   

13

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

ฉันยังห่อมันด้วยวิธีการทั่วไปเนื่องจากฉันกำลังสร้างไฟล์ xml ขนาดใหญ่มากซึ่งมีขนาดใหญ่เกินไปที่จะทำให้เป็นอนุกรมในหน่วยความจำดังนั้นฉันจึงทำลายไฟล์เอาต์พุตของฉันลงและทำให้เป็นอนุกรมใน "ชิ้น" ที่เล็กกว่า:

    public static string XmlSerialize<T>(T entity) where T : class
    {
        // removes version
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;

        XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
        using (StringWriter sw = new StringWriter())
        using (XmlWriter writer = XmlWriter.Create(sw, settings))
        {
            // removes namespace
            var xmlns = new XmlSerializerNamespaces();
            xmlns.Add(string.Empty, string.Empty);

            xsSubmit.Serialize(writer, entity, xmlns);
            return sw.ToString(); // Your XML
        }
    }

ระวังStringWriterค่าเริ่มต้นคือการเข้ารหัส UTF-16 ซึ่งอาจนำไปสู่ปัญหา deserialization ดาวน์สตรีม using (var reader = XmlReader.Create(stream)){ reader.Read(); }สิ่งนี้ทำให้เกิดข้อยกเว้นเนื่องจากการประกาศระบุว่าเป็น UTF-16 ในขณะที่เนื้อหาถูกเขียนเป็น UTF-8 System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
Tyler StandishMan

หากต้องการหลีกเลี่ยงปัญหานี้และยังคงใช้อยู่XmlReaderคุณสามารถใช้var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);The true จะใช้ BOM หากพบมิฉะนั้นจะเป็นค่าเริ่มต้นที่คุณระบุ
Tyler StandishMan

9

ฉันขอแนะนำคลาสตัวช่วยนี้:

public static class Xml
{
    #region Fields

    private static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings {OmitXmlDeclaration = true, Indent = true};
    private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")});

    #endregion

    #region Methods

    public static string Serialize(object obj)
    {
        if (obj == null)
        {
            return null;
        }

        return DoSerialize(obj);
    }

    private static string DoSerialize(object obj)
    {
        using (var ms = new MemoryStream())
        using (var writer = XmlWriter.Create(ms, WriterSettings))
        {
            var serializer = new XmlSerializer(obj.GetType());
            serializer.Serialize(writer, obj, Namespaces);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }

    public static T Deserialize<T>(string data)
        where T : class
    {
        if (string.IsNullOrEmpty(data))
        {
            return null;
        }

        return DoDeserialize<T>(data);
    }

    private static T DoDeserialize<T>(string data) where T : class
    {
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
        {
            var serializer = new XmlSerializer(typeof (T));
            return (T) serializer.Deserialize(ms);
        }
    }

    #endregion
}

:)


คำตอบที่ดี :) ฉันยังเพิ่มสตรีมบรรทัดนี้ตำแหน่ง = 0; และส่งคืนสตรีมทั้งหมดในโซลูชันของฉัน .. ทำงานได้ตามที่คาดไว้ - แท็กการชะลอตัวทั้งหมดถูกลบออก
ymz

การเพิ่มอาร์กิวเมนต์เนมสเปซให้กับการเรียกซีเรียลไลเซอร์เพียงอย่างเดียวทำให้ฉันสามารถลบเนมสเปซเริ่มต้นได้ การเขียนnew XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty})แทนnew XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})เป็นวิธีที่ชัดเจนโดยเจตนาในการเขียนโค้ดในความคิดของฉัน
Suncat2000

5

หากคุณไม่สามารถกำจัดแอตทริบิวต์ xmlns พิเศษสำหรับแต่ละองค์ประกอบได้เมื่อทำให้อนุกรมเป็น xml จากคลาสที่สร้างขึ้น (เช่น: เมื่อใช้xsd.exe ) ดังนั้นคุณจึงมีสิ่งที่ต้องการ:

<manyElementWith xmlns="urn:names:specification:schema:xsd:one" />

จากนั้นฉันจะแบ่งปันสิ่งที่ได้ผลกับฉัน (คำตอบก่อนหน้านี้ผสมผสานกับสิ่งที่ฉันพบที่นี่ )

ตั้งค่า xmlns ที่แตกต่างกันทั้งหมดของคุณอย่างชัดเจนดังนี้:

Dim xmlns = New XmlSerializerNamespaces()
xmlns.Add("one", "urn:names:specification:schema:xsd:one")
xmlns.Add("two",  "urn:names:specification:schema:xsd:two")
xmlns.Add("three",  "urn:names:specification:schema:xsd:three")

จากนั้นส่งต่อไปยังซีเรียลไลซ์

serializer.Serialize(writer, object, xmlns);

คุณจะมีสามเนมสเปซที่ประกาศไว้ในองค์ประกอบรูทและไม่จำเป็นต้องสร้างขึ้นในองค์ประกอบอื่น ๆ อีกต่อไปซึ่งจะนำหน้าตามนั้น

<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
   <one:Element />
   <two:ElementFromAnotherNameSpace /> ...

0
        XmlWriterSettings settings = new XmlWriterSettings
        {
            OmitXmlDeclaration = true
        };

        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");

        StringBuilder sb = new StringBuilder();

        XmlSerializer xs = new XmlSerializer(typeof(BankingDetails));

        using (XmlWriter xw = XmlWriter.Create(sb, settings))
        {
            xs.Serialize(xw, model, ns);
            xw.Flush();
            return sb.ToString();
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.