เนื่องจาก Dave ขอให้ฉันตอบซ้ำการละเว้นเนมสเปซ xsi และ xsd ทั้งหมดเมื่อทำให้เป็นอนุกรมวัตถุใน. NETฉันจึงอัปเดตโพสต์นี้และตอบซ้ำที่นี่จากลิงค์ที่กล่าวถึงข้างต้น ตัวอย่างที่ใช้ในคำตอบนี้เป็นตัวอย่างเดียวกับที่ใช้สำหรับคำถามอื่น สิ่งต่อไปนี้คือการคัดลอกคำต่อคำ
หลังจากอ่านเอกสารของ Microsoft และวิธีแก้ปัญหาต่างๆทางออนไลน์ฉันได้ค้นพบวิธีแก้ปัญหานี้ ทำงานได้กับทั้งการXmlSerializer
จัดลำดับ XML ในตัวและแบบกำหนดเองผ่านทางIXmlSerialiazble
.
เพื่อเล็กน้อยฉันจะใช้MyTypeWithNamespaces
ตัวอย่าง XML เดียวกับที่ใช้ในคำตอบของคำถามนี้จนถึงตอนนี้
[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;
}
นั่นคือทั้งหมดสำหรับชั้นเรียนนี้ ตอนนี้บางคนคัดค้านที่จะมีไฟล์XmlSerializerNamespaces
วัตถุอยู่ในชั้นเรียนของตน แต่อย่างที่คุณเห็นฉันซ่อนมันไว้อย่างเรียบร้อยในตัวสร้างเริ่มต้นและเปิดเผยทรัพย์สินสาธารณะเพื่อส่งคืนเนมสเปซ
ตอนนี้เมื่อถึงเวลาที่ต้องทำให้คลาสเป็นลำดับคุณจะต้องใช้รหัสต่อไปนี้:
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);
เมื่อคุณทำเสร็จแล้วคุณจะได้ผลลัพธ์ดังต่อไปนี้:
<MyTypeWithNamespaces>
<Label xmlns="urn:Whoohoo">myLabel</Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
ฉันใช้วิธีนี้สำเร็จแล้วในโปรเจ็กต์ล่าสุดที่มีคลาสแบบลึกที่ต่ออนุกรมกับ XML สำหรับการเรียกใช้บริการเว็บ เอกสารของ Microsoft ไม่ชัดเจนว่าจะทำอย่างไรกับXmlSerializerNamespaces
สมาชิกที่เข้าถึงได้แบบสาธารณะเมื่อคุณสร้างมันขึ้นมาและหลายคนคิดว่ามันไม่มีประโยชน์ แต่ต่อไปนี้เอกสารของพวกเขาและใช้มันในลักษณะที่แสดงข้างต้นคุณสามารถกำหนดวิธีการ XmlSerializer สร้าง XML สำหรับชั้นเรียนของคุณโดยไม่ต้อง resorting พฤติกรรมที่ไม่สนับสนุนหรือ "กลิ้งของคุณเอง" IXmlSerializable
เป็นอันดับโดยการใช้
ฉันหวังเป็นอย่างยิ่งว่าคำตอบนี้จะนำไปสู่ความสงบในทันทีวิธีกำจัดมาตรฐานxsi
และxsd
เนมสเปซที่สร้างโดยไฟล์XmlSerializer
.
UPDATE: ฉันแค่ต้องการให้แน่ใจว่าฉันตอบคำถามของ OP เกี่ยวกับการลบเนมสเปซทั้งหมด รหัสของฉันด้านบนจะใช้ได้กับสิ่งนี้ ให้ฉันแสดงวิธี ตอนนี้ในตัวอย่างข้างต้นคุณไม่สามารถกำจัดเนมสเปซทั้งหมดได้ (เนื่องจากมีการใช้งานเนมสเปซสองชื่อ) ที่ไหนสักแห่งในเอกสาร XML ของคุณคุณจะต้องมีบางอย่างเช่นxmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo
. ถ้าชั้นในตัวอย่างที่เป็นส่วนหนึ่งของเอกสารที่มีขนาดใหญ่แล้วที่ไหนสักแห่งข้างต้น namespace ต้องได้รับการประกาศอย่างใดอย่างหนึ่งอย่างใดอย่างหนึ่ง (หรือทั้งสอง) และAbracadbra
Whoohoo
ถ้าไม่เช่นนั้นองค์ประกอบในเนมสเปซหนึ่งหรือทั้งสองจะต้องได้รับการตกแต่งด้วยคำนำหน้าของการจัดเรียงบางประเภท (คุณไม่สามารถมีเนมสเปซเริ่มต้นสองรายการได้ใช่ไหม) ดังนั้นสำหรับตัวอย่างนี้Abracadabra
คือเนมสเปซเริ่มต้น ฉันสามารถMyTypeWithNamespaces
เพิ่มคำนำหน้าเนมสเปซภายในชั้นเรียนของฉันได้Whoohoo
ดังนี้:
public MyTypeWithNamespaces
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
new XmlQualifiedName(string.Empty, "urn:Abracadabra"), // Default Namespace
new XmlQualifiedName("w", "urn:Whoohoo")
});
}
ตอนนี้ในนิยามคลาสของฉันฉันระบุว่า<Label/>
องค์ประกอบนั้นอยู่ในเนมสเปซ"urn:Whoohoo"
ดังนั้นฉันจึงไม่จำเป็นต้องทำอะไรเพิ่มเติม เมื่อตอนนี้ฉันจัดลำดับคลาสโดยใช้รหัสซีเรียลไลเซชั่นด้านบนของฉันไม่เปลี่ยนแปลงนี่คือผลลัพธ์:
<MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
<w:Label>myLabel</w:Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
เนื่องจาก<Label>
อยู่ในเนมสเปซที่แตกต่างจากส่วนที่เหลือของเอกสารจึงต้อง "ตกแต่ง" ด้วยเนมสเปซในบางครั้ง สังเกตว่ายังไม่มีxsi
และxsd
เนมสเปซ
นี่เป็นการสิ้นสุดคำตอบของฉันสำหรับคำถามอื่น แต่ฉันต้องการให้แน่ใจว่าฉันตอบคำถามของ OP เกี่ยวกับการใช้เนมสเปซไม่ได้เพราะฉันรู้สึกว่าฉันยังไม่ได้พูดถึงมันจริงๆ สมมติว่า<Label>
เป็นส่วนหนึ่งของเนมสเปซเดียวกับส่วนที่เหลือของเอกสารในกรณีนี้urn:Abracadabra
:
<MyTypeWithNamespaces>
<Label>myLabel<Label>
<Epoch>42</Epoch>
</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[] {
new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
});
}
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
get { return this._namespaces; }
}
private XmlSerializerNamespaces _namespaces;
จากนั้นในรหัสของคุณที่ใช้MyTypeWithNamespaces
วัตถุในการทำให้เป็นอนุกรมคุณจะเรียกมันตามที่ฉันทำด้านบน:
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);
และสิ่งXmlSerializer
นี้จะคาย XML เดียวกันดังที่แสดงไว้ด้านบนทันทีโดยไม่มีเนมสเปซเพิ่มเติมในเอาต์พุต:
<MyTypeWithNamespaces>
<Label>myLabel<Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>