Bỏ qua tất cả các không gian tên xsi và xsd khi tuần tự hóa một đối tượng trong .NET?


132

Mã trông như thế này:

StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using (XmlWriter xmlWriter = XmlWriter.Create(builder, settings))
{
    XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
    s.Serialize(xmlWriter, objectToSerialize);
}

Tài liệu nối tiếp kết quả bao gồm các không gian tên, như vậy:

<message xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 
    xmlns="urn:something">
 ...
</message>

Để loại bỏ các không gian tên xsi và xsd, tôi có thể làm theo câu trả lời từ Làm thế nào để tuần tự hóa một đối tượng thành XML mà không nhận được xmlns = Hồi lỗi? .

Tôi muốn thẻ thông báo của mình là <message>(không có bất kỳ thuộc tính không gian tên nào). Tôi có thể làm cái này như thế nào?


2
Tôi biết bạn nghĩ rằng điều này có thể làm cho xml của bạn trông đẹp hơn, nhưng cung cấp không gian tên và xsd tương ứng là cách tốt hơn.

2
Tôi chỉ muốn xml của mình dưới dạng <message>, tôi đang nói về việc bỏ qua các không gian tên xmlns: xsi và xmlns: xsd.
NetSide

5
Đối với hồ sơ: Nói chung, đây là một sai lầm ngu ngốc. Các không gian tên là có lý do, và loại bỏ tất cả chúng sẽ phá vỡ mọi thứ. Những thứ như khử lưu huỳnh.
John Saunders

66
Lưu ý rằng đôi khi nó không ngu ngốc và không phải là một sai lầm. Ví dụ, người ta có thể cần tạo ra các đoạn tài liệu và đặt chúng lại với nhau sau này. Cá nhân, tôi cần tạo ra rất nhiều tài liệu tương tự và rất lớn. Tất cả chúng đều có cùng một phần lớn nằm sâu bên trong cây. Vì vậy, tôi đã phải tạo ra các phần bất biến trước đó và chèn chúng dưới dạng mảng byte khi tạo tài liệu. Vì vậy, để làm cho đầu ra dễ đọc hơn và nhỏ hơn, tôi cần bỏ qua một số khai báo không gian tên trong các phần bên trong vì chúng tồn tại ở các mức cao hơn.
Dmitry Tashkinov

Câu trả lời:


233
...
XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("","");
s.Serialize(xmlWriter, objectToSerialize, ns);

2
Tôi chỉ muốn thêm rằng việc loại bỏ không gian tên mặc định có thể gây ra hậu quả ngoài ý muốn: ví dụ: nếu bạn sử dụng thuộc tính XmlInclude để tuần tự hóa các loại dẫn xuất, các không gian tên sẽ được thêm vào từng phần tử này, cho dù bạn có muốn hay không, bởi vì chúng 'cần thiết cho quá trình khử lưu huỳnh
Thomas Levesque

3
Ngoài ra, điều này không loại bỏ tất cả các không gian tên xml, như câu hỏi được hỏi. Nó chỉ xóa các không gian tên xsi và xsd, như được đề cập trong câu hỏi stackoverflow.com/questions/258960 , cũng được trích dẫn trong câu hỏi này .
Cheeso

1
Cũng không được hỗ trợ bởi MS như đã đề cập trong câu trả lời của riêng tôi. Nó không phải luôn luôn làm việc, đặc biệt là khi loại của bạn có thể được sử dụng với những người khác mà làm có không gian tên.
Fourpastmidnight 18/07/13

@ThomasLevesque, làm cách nào để xóa không gian tên mặc định trong khi sử dụng thuộc tính XmlInclude?
Jeson Martajaya

4
Có thể rút ngắn thànhs.Serialize(writer, objectToSerialize, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty }));
Xeevis

27

Đây là câu trả lời thứ 2.

Nếu bạn muốn loại bỏ tất cả các không gian tên tùy ý khỏi một tài liệu trong quá trình tuần tự hóa, bạn có thể thực hiện việc này bằng cách triển khai XmlWriter của riêng bạn.

Cách dễ nhất là lấy từ XmlTextWriter và ghi đè phương thức StartEuity phát ra các không gian tên. Phương thức StartEuity được XmlSerializer gọi ra khi phát ra bất kỳ phần tử nào, kể cả root. Bằng cách ghi đè không gian tên cho từng thành phần và thay thế nó bằng chuỗi trống, bạn đã loại bỏ các không gian tên khỏi đầu ra.

public class NoNamespaceXmlWriter : XmlTextWriter
{
    //Provide as many contructors as you need
    public NoNamespaceXmlWriter(System.IO.TextWriter output)
        : base(output) { Formatting= System.Xml.Formatting.Indented;}

    public override void WriteStartDocument () { }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        base.WriteStartElement("", localName, "");
    }
}

Giả sử đây là loại:

// explicitly specify a namespace for this type,
// to be used during XML serialization.
[XmlRoot(Namespace="urn:Abracadabra")]
public class MyTypeWithNamespaces
{
    // private fields backing the properties
    private int _Epoch;
    private string _Label;

    // explicitly define a distinct namespace for this element
    [XmlElement(Namespace="urn:Whoohoo")]
    public string Label
    {
        set {  _Label= value; } 
        get { return _Label; } 
    }

    // this property will be implicitly serialized to XML using the
    // member name for the element name, and inheriting the namespace from
    // the type.
    public int Epoch
    {
        set {  _Epoch= value; } 
        get { return _Epoch; } 
    }
}

Đây là cách bạn sẽ sử dụng một thứ như vậy trong quá trình tuần tự hóa:

        var o2= new MyTypeWithNamespaces { ..intializers.. };
        var builder = new System.Text.StringBuilder();
        using ( XmlWriter writer = new NoNamespaceXmlWriter(new System.IO.StringWriter(builder)))
        {
            s2.Serialize(writer, o2, ns2);
        }            
        Console.WriteLine("{0}",builder.ToString());

Mặc dù vậy, XmlTextWriter bị hỏng. Theo tài liệu tham khảo , khi viết nó không kiểm tra các mục sau:

  • Các ký tự không hợp lệ trong tên thuộc tính và thành phần.

  • Các ký tự Unicode không phù hợp với mã hóa được chỉ định. Nếu các ký tự Unicode không phù hợp với mã hóa được chỉ định, XmlTextWriter không thoát các ký tự Unicode thành các thực thể ký tự.

  • Thuộc tính trùng lặp.

  • Các ký tự trong mã định danh công khai DOCTYPE hoặc mã định danh hệ thống.

Các vấn đề với XmlTextWriter đã xuất hiện từ v1.1 của .NET Framework và chúng sẽ vẫn còn, để tương thích ngược. Nếu bạn không có lo ngại về những vấn đề đó, thì bằng mọi cách, hãy sử dụng XmlTextWriter. Nhưng hầu hết mọi người muốn có độ tin cậy cao hơn một chút.

Để có được điều đó, trong khi vẫn triệt tiêu các không gian tên trong quá trình tuần tự hóa, thay vì xuất phát từ XmlTextWriter, hãy xác định một triển khai cụ thể của XmlWriter trừu tượng và 24 phương thức của nó.

Một ví dụ ở đây:

public class XmlWriterWrapper : XmlWriter
{
    protected XmlWriter writer;

    public XmlWriterWrapper(XmlWriter baseWriter)
    {
        this.Writer = baseWriter;
    }

    public override void Close()
    {
        this.writer.Close();
    }

    protected override void Dispose(bool disposing)
    {
        ((IDisposable) this.writer).Dispose();
    }

    public override void Flush()
    {
        this.writer.Flush();
    }

    public override string LookupPrefix(string ns)
    {
        return this.writer.LookupPrefix(ns);
    }

    public override void WriteBase64(byte[] buffer, int index, int count)
    {
        this.writer.WriteBase64(buffer, index, count);
    }

    public override void WriteCData(string text)
    {
        this.writer.WriteCData(text);
    }

    public override void WriteCharEntity(char ch)
    {
        this.writer.WriteCharEntity(ch);
    }

    public override void WriteChars(char[] buffer, int index, int count)
    {
        this.writer.WriteChars(buffer, index, count);
    }

    public override void WriteComment(string text)
    {
        this.writer.WriteComment(text);
    }

    public override void WriteDocType(string name, string pubid, string sysid, string subset)
    {
        this.writer.WriteDocType(name, pubid, sysid, subset);
    }

    public override void WriteEndAttribute()
    {
        this.writer.WriteEndAttribute();
    }

    public override void WriteEndDocument()
    {
        this.writer.WriteEndDocument();
    }

    public override void WriteEndElement()
    {
        this.writer.WriteEndElement();
    }

    public override void WriteEntityRef(string name)
    {
        this.writer.WriteEntityRef(name);
    }

    public override void WriteFullEndElement()
    {
        this.writer.WriteFullEndElement();
    }

    public override void WriteProcessingInstruction(string name, string text)
    {
        this.writer.WriteProcessingInstruction(name, text);
    }

    public override void WriteRaw(string data)
    {
        this.writer.WriteRaw(data);
    }

    public override void WriteRaw(char[] buffer, int index, int count)
    {
        this.writer.WriteRaw(buffer, index, count);
    }

    public override void WriteStartAttribute(string prefix, string localName, string ns)
    {
        this.writer.WriteStartAttribute(prefix, localName, ns);
    }

    public override void WriteStartDocument()
    {
        this.writer.WriteStartDocument();
    }

    public override void WriteStartDocument(bool standalone)
    {
        this.writer.WriteStartDocument(standalone);
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        this.writer.WriteStartElement(prefix, localName, ns);
    }

    public override void WriteString(string text)
    {
        this.writer.WriteString(text);
    }

    public override void WriteSurrogateCharEntity(char lowChar, char highChar)
    {
        this.writer.WriteSurrogateCharEntity(lowChar, highChar);
    }

    public override void WriteValue(bool value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(DateTime value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(decimal value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(double value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(int value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(long value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(object value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(float value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(string value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteWhitespace(string ws)
    {
        this.writer.WriteWhitespace(ws);
    }


    public override XmlWriterSettings Settings
    {
        get
        {
            return this.writer.Settings;
        }
    }

    protected XmlWriter Writer
    {
        get
        {
            return this.writer;
        }
        set
        {
            this.writer = value;
        }
    }

    public override System.Xml.WriteState WriteState
    {
        get
        {
            return this.writer.WriteState;
        }
    }

    public override string XmlLang
    {
        get
        {
            return this.writer.XmlLang;
        }
    }

    public override System.Xml.XmlSpace XmlSpace
    {
        get
        {
            return this.writer.XmlSpace;
        }
    }        
}

Sau đó, cung cấp một lớp dẫn xuất ghi đè phương thức StartEuity, như trước:

public class NamespaceSupressingXmlWriter : XmlWriterWrapper
{
    //Provide as many contructors as you need
    public NamespaceSupressingXmlWriter(System.IO.TextWriter output)
        : base(XmlWriter.Create(output)) { }

    public NamespaceSupressingXmlWriter(XmlWriter output)
        : base(XmlWriter.Create(output)) { }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        base.WriteStartElement("", localName, "");
    }
}

Và sau đó sử dụng nhà văn này như vậy:

        var o2= new MyTypeWithNamespaces { ..intializers.. };
        var builder = new System.Text.StringBuilder();
        var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
        using ( XmlWriter innerWriter = XmlWriter.Create(builder, settings))
            using ( XmlWriter writer = new NamespaceSupressingXmlWriter(innerWriter))
            {
                s2.Serialize(writer, o2, ns2);
            }            
        Console.WriteLine("{0}",builder.ToString());

Tín dụng cho điều này cho Oleg Tkachenko .


3
Tôi thấy rằng tôi cũng cần ghi đè LookupPrefix(string ns)để luôn trả về một chuỗi rỗng để xóa tất cả các khai báo lược đồ.
Kevin Brock

Điều này về mặt kỹ thuật không trả lời câu hỏi - bạn đang sử dụng XmlTextWriter, không phải XmlWriter. Tôi nhận thấy vì tôi muốn sử dụng XmlWriter, cho XmlWriterS Settings mà tôi có thể sử dụng với nó.
Bàn tính

@ Abacus bạn đã đọc mã? Nó sử dụng XmlWriter XmlWriterSettings .
Cheeso

xấu của tôi, tôi đã phải bỏ lỡ điều đó.
Bàn tính

Câu trả lời tuyệt vời, Ngoài phương thức được thêm từ @KevinBrock, tôi cũng cần phải quá tải <! - ngôn ngữ: lang-cs -> WriteStartAttribution (tiền tố chuỗi, chuỗi localName, chuỗi ns) trước khi mã của tôi loại bỏ tất cả không gian tên. Cũng đáng chú ý tiền tố không gian tên của tôi đã thay đổi từ b2p1 sang p2, điều này khiến tôi phải kiểm tra các phương thức khác bằng cách sử dụng tiền tố.
Mabdullah

15

Sau khi đọc tài liệu của Microsoft và một số giải pháp trực tuyến, tôi đã phát hiện ra giải pháp cho vấn đề này. Nó hoạt động với cả XmlSerializertuần tự hóa XML tích hợp và tùy chỉnh thông qua IXmlSerialiazble.

Để dí dỏm, tôi sẽ sử dụng cùng một MyTypeWithNamespacesmẫu XML đã được sử dụng trong các câu trả lời cho câu hỏi này cho đến nay.

[XmlRoot("MyTypeWithNamespaces", Namespace="urn:Abracadabra", IsNullable=false)]
public class MyTypeWithNamespaces
{
    // As noted below, per Microsoft's documentation, if the class exposes a public
    // member of type XmlSerializerNamespaces decorated with the 
    // XmlNamespacesDeclarationAttribute, then the XmlSerializer will utilize those
    // namespaces during serialization.
    public MyTypeWithNamespaces( )
    {
        this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
            // Don't do this!! Microsoft's documentation explicitly says it's not supported.
            // It doesn't throw any exceptions, but in my testing, it didn't always work.

            // new XmlQualifiedName(string.Empty, string.Empty),  // And don't do this:
            // new XmlQualifiedName("", "")

            // DO THIS:
            new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
            // Add any other namespaces, with prefixes, here.
        });
    }

    // If you have other constructors, make sure to call the default constructor.
    public MyTypeWithNamespaces(string label, int epoch) : this( )
    {
        this._label = label;
        this._epoch = epoch;
    }

    // An element with a declared namespace different than the namespace
    // of the enclosing type.
    [XmlElement(Namespace="urn:Whoohoo")]
    public string Label
    {
        get { return this._label; }
        set { this._label = value; }
    }
    private string _label;

    // An element whose tag will be the same name as the property name.
    // Also, this element will inherit the namespace of the enclosing type.
    public int Epoch
    {
        get { return this._epoch; }
        set { this._epoch = value; }
    }
    private int _epoch;

    // Per Microsoft's documentation, you can add some public member that
    // returns a XmlSerializerNamespaces object. They use a public field,
    // but that's sloppy. So I'll use a private backed-field with a public
    // getter property. Also, per the documentation, for this to work with
    // the XmlSerializer, decorate it with the XmlNamespaceDeclarations
    // attribute.
    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces Namespaces
    {
        get { return this._namespaces; }
    }
    private XmlSerializerNamespaces _namespaces;
}

Đó là tất cả cho lớp học này. Bây giờ, một số người phản đối việc có một XmlSerializerNamespacesđối tượng ở đâu đó trong các lớp của họ; nhưng như bạn có thể thấy, tôi đã giấu nó gọn gàng trong hàm tạo mặc định và hiển thị một thuộc tính công cộng để trả về các không gian tên.

Bây giờ, khi đến lúc nối tiếp lớp, bạn sẽ sử dụng đoạn mã sau:

MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);

/******
   OK, I just figured I could do this to make the code shorter, so I commented out the
   below and replaced it with what follows:

// You have to use this constructor in order for the root element to have the right namespaces.
// If you need to do custom serialization of inner objects, you can use a shortened constructor.
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces), new XmlAttributeOverrides(),
    new Type[]{}, new XmlRootAttribute("MyTypeWithNamespaces"), "urn:Abracadabra");

******/
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
    new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });

// I'll use a MemoryStream as my backing store.
MemoryStream ms = new MemoryStream();

// This is extra! If you want to change the settings for the XmlSerializer, you have to create
// a separate XmlWriterSettings object and use the XmlTextWriter.Create(...) factory method.
// So, in this case, I want to omit the XML declaration.
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Encoding = Encoding.UTF8; // This is probably the default
// You could use the XmlWriterSetting to set indenting and new line options, but the
// XmlTextWriter class has a much easier method to accomplish that.

// The factory method returns a XmlWriter, not a XmlTextWriter, so cast it.
XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws);
// Then we can set our indenting options (this is, of course, optional).
xtw.Formatting = Formatting.Indented;

// Now serialize our object.
xs.Serialize(xtw, myType, myType.Namespaces);

Một khi bạn đã làm điều này, bạn sẽ nhận được đầu ra sau đây:

<MyTypeWithNamespaces>
    <Label xmlns="urn:Whoohoo">myLabel</Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

Tôi đã sử dụng thành công phương thức này trong một dự án gần đây với một loạt các lớp được tuần tự hóa thành XML cho các cuộc gọi dịch vụ web. Tài liệu của Microsoft không rõ ràng về việc phải làm gì với XmlSerializerNamespacesthành viên bị cáo buộc công khai một khi bạn đã tạo ra nó và rất nhiều người nghĩ rằng nó vô dụng. Nhưng bằng cách làm theo tài liệu của họ và sử dụng nó theo cách hiển thị ở trên, bạn có thể tùy chỉnh cách XmlSerializer tạo XML cho các lớp của bạn mà không cần dùng đến hành vi không được hỗ trợ hoặc "tuần tự hóa" của riêng bạn bằng cách triển khai IXmlSerializable.

Tôi hy vọng rằng câu trả lời này sẽ được đặt vào phần còn lại, một lần và mãi mãi, làm thế nào để thoát khỏi tiêu chuẩn xsixsdkhông gian tên được tạo bởi XmlSerializer.

CẬP NHẬT: Tôi chỉ muốn đảm bảo rằng tôi đã trả lời câu hỏi của OP về việc xóa tất cả các không gian tên. Mã của tôi ở trên sẽ làm việc cho điều này; Hãy để tôi chỉ cho bạn cách làm. Bây giờ, trong ví dụ trên, bạn thực sự không thể thoát khỏi tất cả các không gian tên (vì có hai không gian tên được sử dụng). Ở đâu đó trong tài liệu XML của bạn, bạn sẽ cần phải có một cái gì đó như thế xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo. Nếu lớp trong ví dụ là một phần của tài liệu lớn hơn, thì ở đâu đó phía trên một không gian tên phải được khai báo cho một trong hai (hoặc cả hai) AbracadbraWhoohoo. Nếu không, thì phần tử trong một hoặc cả hai không gian tên phải được trang trí bằng một tiền tố của một loại nào đó (bạn không thể có hai không gian tên mặc định, phải không?). Vì vậy, trong ví dụ này, Abracadabralà không gian tên defalt. Tôi có thể bên trong MyTypeWithNamespaceslớp mình thêm tiền tố không gian tên cho Whoohookhông gian tên như vậy:

public MyTypeWithNamespaces
{
    this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
        new XmlQualifiedName(string.Empty, "urn:Abracadabra"), // Default Namespace
        new XmlQualifiedName("w", "urn:Whoohoo")
    });
}

Bây giờ, trong định nghĩa lớp của tôi, tôi đã chỉ ra rằng <Label/>phần tử nằm trong không gian tên "urn:Whoohoo", vì vậy tôi không cần phải làm gì thêm. Khi tôi bây giờ tuần tự hóa lớp sử dụng mã tuần tự hóa ở trên của tôi không thay đổi, đây là đầu ra:

<MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
    <w:Label>myLabel</w:Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

Bởi vì <Label>trong một không gian tên khác với phần còn lại của tài liệu, nên trong một ngày nào đó, nó phải được "trang trí" bằng một không gian tên. Lưu ý rằng vẫn không có xsixsdkhông gian tên.


"Tài liệu của Microsoft nói rõ rằng nó không được hỗ trợ." Muốn chia sẻ ở đâu?
Dave Van den Eynde

Dave, như bạn đã đăng trên câu trả lời của tôi cho một câu hỏi tương tự, XmlSerializer: loại bỏ các không gian tên xsi và xsd không cần thiết , liên kết có ở đây: XmlSerializerNamespaces Class .
Fourpastmidnight

1
Bạn vẫn đang truyền các không gian tên cho phương thức Nối tiếp. Tôi nghĩ ý tưởng cung cấp một thành viên Công cộng là bạn sẽ không phải làm điều đó? Tôi không thể làm cho nó hoạt động mặc dù không chuyển nó sang phương thức Nối tiếp. Và thật không may, tôi không có quyền truy cập vào cuộc gọi phương thức đó. Tôi chỉ có thể đặt phiên bản XmlSerializer để sử dụng.
nghiền nát

Tôi thấy rằng đó thực sự là XmlWritercái được chứa trong các XmlMediaTypeFormatterkhông gian tên xsi và xsd vào đầu ra của tôi bất kể. Điều này chỉ ảnh hưởng đến những người sử dụng mặc định của WebApi XmlMediaTypeFormatter. Tôi đã sao chép mã nguồn cho nó và sửa đổi nó để chuyển thuộc tính Không gian tên của tôi sang phương thức Nối tiếp theo yêu cầu để ngăn không cho XmlWritertự động thêm hai mặc định. Xem câu trả lời này
nghiền nát

@crush, câu trả lời mà bạn liên kết đến là sai lệch - không sai, nhưng khẳng định của nó không hoàn toàn chính xác. Nếu bạn nhìn vào đoạn mã đầu tiên trong câu trả lời của tôi, bạn sẽ thấy một nhận xét nêu rõ cách thức XmlSerializer hoạt động khi bạn hiển thị một thành viên công khai thuộc loại XmlSerializerNamespacesđược trang trí bằng XmlNamespacesDeclarationAttribute. Điều này được lấy trực tiếp từ MSDN và về cơ bản sử dụng các không gian tên được khai báo thay cho các không gian tên mặc định được cung cấp bởi XmlSerializer.
bốnpastmidnight

6

Đây là câu trả lời đầu tiên trong hai câu hỏi của tôi.

Nếu bạn muốn kiểm soát tốt các không gian tên - ví dụ: nếu bạn muốn bỏ qua một số trong số chúng nhưng không phải là không gian khác hoặc nếu bạn muốn thay thế một không gian tên bằng một không gian tên khác, bạn có thể thực hiện việc này bằng XmlAttributionOverrides .

Giả sử bạn có định nghĩa loại này:

// explicitly specify a namespace for this type,
// to be used during XML serialization.
[XmlRoot(Namespace="urn:Abracadabra")]
public class MyTypeWithNamespaces
{
    // private fields backing the properties
    private int _Epoch;
    private string _Label;

    // explicitly define a distinct namespace for this element
    [XmlElement(Namespace="urn:Whoohoo")]
    public string Label
    {
        set {  _Label= value; } 
        get { return _Label; } 
    }

    // this property will be implicitly serialized to XML using the
    // member name for the element name, and inheriting the namespace from
    // the type.
    public int Epoch
    {
        set {  _Epoch= value; } 
        get { return _Epoch; } 
    }
}

Và mã giả này được xê-ri hóa:

        var o2= new MyTypeWithNamespaces() { ..initializers...};
        ns.Add( "", "urn:Abracadabra" );
        XmlSerializer s2 = new XmlSerializer(typeof(MyTypeWithNamespaces));
        s2.Serialize(System.Console.Out, o2, ns);

Bạn sẽ nhận được một cái gì đó như XML này:

<MyTypeWithNamespaces xmlns="urn:Abracadabra">
  <Label xmlns="urn:Whoohoo">Cimsswybclaeqjh</Label>
  <Epoch>97</Epoch>
</MyTypeWithNamespaces>

Lưu ý rằng có một không gian tên mặc định trên phần tử gốc và cũng có một không gian tên riêng biệt trên phần tử "Nhãn". Các không gian tên này được quyết định bởi các thuộc tính trang trí loại, trong mã ở trên.

Khung nối tiếp Xml trong .NET bao gồm khả năng ghi đè rõ ràng các thuộc tính trang trí mã thực tế. Bạn làm điều này với lớp XmlAttributOverrides và bạn bè. Giả sử tôi có cùng loại và tôi tuần tự hóa nó theo cách này:

        // instantiate the container for all attribute overrides
        XmlAttributeOverrides xOver = new XmlAttributeOverrides();

        // define a set of XML attributes to apply to the root element
        XmlAttributes xAttrs1 = new XmlAttributes();

        // define an XmlRoot element (as if [XmlRoot] had decorated the type)
        // The namespace in the attribute override is the empty string. 
        XmlRootAttribute xRoot = new XmlRootAttribute() { Namespace = ""};

        // add that XmlRoot element to the container of attributes
        xAttrs1.XmlRoot= xRoot;

        // add that bunch of attributes to the container holding all overrides
        xOver.Add(typeof(MyTypeWithNamespaces), xAttrs1);

        // create another set of XML Attributes
        XmlAttributes xAttrs2 = new XmlAttributes();

        // define an XmlElement attribute, for a type of "String", with no namespace
        var xElt = new XmlElementAttribute(typeof(String)) { Namespace = ""};

        // add that XmlElement attribute to the 2nd bunch of attributes
        xAttrs2.XmlElements.Add(xElt);

        // add that bunch of attributes to the container for the type, and
        // specifically apply that bunch to the "Label" property on the type.
        xOver.Add(typeof(MyTypeWithNamespaces), "Label", xAttrs2);

        // instantiate a serializer with the overrides 
        XmlSerializer s3 = new XmlSerializer(typeof(MyTypeWithNamespaces), xOver);

        // serialize
        s3.Serialize(System.Console.Out, o2, ns2);

Kết quả trông như thế này;

<MyTypeWithNamespaces>
  <Label>Cimsswybclaeqjh</Label>
  <Epoch>97</Epoch>
</MyTypeWithNamespaces>

Bạn đã loại bỏ các không gian tên.

Một câu hỏi hợp lý là, bạn có thể loại bỏ tất cả các không gian tên từ các loại tùy ý trong quá trình tuần tự hóa, mà không cần thông qua các ghi đè rõ ràng không? Câu trả lời là CÓ, và làm thế nào để có nó trong phản hồi tiếp theo của tôi.


6
XmlSerializer sr = new XmlSerializer(objectToSerialize.GetType());
TextWriter xmlWriter = new StreamWriter(filename);
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
sr.Serialize(xmlWriter, objectToSerialize, namespaces);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.