Vì Dave yêu cầu tôi lặp lại câu trả lời của mình để 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 , tôi đã cập nhật bài đăng này và lặp lại câu trả lời của tôi ở đây từ liên kết được đề cập ở trên. Ví dụ được sử dụng trong câu trả lời này là ví dụ tương tự được sử dụng cho câu hỏi khác. Những gì tiếp theo được sao chép, nguyên văn.
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ả XmlSerializer
tuần tự hóa XML tích hợp và tùy chỉnh thông qua IXmlSerialiazble
.
Để làm trắng, tôi sẽ sử dụng cùng một MyTypeWithNamespaces
mẫ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 XmlSerializerNamespaces
thà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 xsi
và xsd
khô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) Abracadbra
và Whoohoo
. 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, Abracadabra
là không gian tên mặc định. Tôi có thể bên trong MyTypeWithNamespaces
lớp mình thêm tiền tố không gian tên cho Whoohoo
khô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ó xsi
và xsd
không gian tên.
Điều này kết thúc câu trả lời của tôi cho câu hỏi khác. Nhưng tôi muốn chắc chắn rằng tôi đã trả lời câu hỏi của OP về việc không sử dụng không gian tên, vì tôi cảm thấy mình chưa thực sự giải quyết nó. Giả sử rằng đó <Label>
là một phần của không gian tên giống như phần còn lại của tài liệu, trong trường hợp này urn:Abracadabra
:
<MyTypeWithNamespaces>
<Label>myLabel<Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
Hàm tạo của bạn sẽ trông giống như trong ví dụ mã đầu tiên của tôi, cùng với thuộc tính công khai để lấy không gian tên mặc định:
// 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[] {
new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
});
}
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
get { return this._namespaces; }
}
private XmlSerializerNamespaces _namespaces;
Sau đó, sau đó, trong mã của bạn sử dụng MyTypeWithNamespaces
đối tượng để tuần tự hóa nó, bạn sẽ gọi nó như tôi đã làm ở trên:
MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });
...
// Above, you'd setup your XmlTextWriter.
// Now serialize our object.
xs.Serialize(xtw, myType, myType.Namespaces);
Và XmlSerializer
sẽ nhổ trở lại cùng một XML như được hiển thị ngay trên đây mà không có không gian tên bổ sung trong đầu ra:
<MyTypeWithNamespaces>
<Label>myLabel<Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>