Dave benden .NET'te bir nesneyi serileştirirken tüm xsi ve xsd ad alanlarının çıkarılması konusundaki cevabımı tekrar etmemi istediğinden, bu yazıyı güncelledim ve cevabımı burada yukarıda belirtilen bağlantıdan tekrarladım. Bu cevapta kullanılan örnek, diğer soru için kullanılan aynı örnektir. Aşağıdakiler kelimesi kelimesine kopyalanır.
Microsoft'un belgelerini ve çeşitli çözümlerini çevrimiçi olarak okuduktan sonra, bu sorunun çözümünü keşfettim. Hem yerleşik hem de XmlSerializer
özel XML serileştirme ile çalışır IXmlSerialiazble
.
Whit için, MyTypeWithNamespaces
şu ana kadar bu sorunun cevaplarında kullanılan XML örneğinin aynısını kullanacağım .
[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;
}
Hepsi bu sınıf için. Şimdi, bazıları birXmlSerializerNamespaces
sınıflarının yerinde nesneye ; ancak görebileceğiniz gibi, onu varsayılan kurucuda özenle sakladım ve ad alanlarını döndürmek için bir genel özelliği açığa çıkardım.
Şimdi, sınıfı serileştirme zamanı geldiğinde, aşağıdaki kodu kullanırsınız:
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);
Bunu yaptıktan sonra aşağıdaki çıktıyı almalısınız:
<MyTypeWithNamespaces>
<Label xmlns="urn:Whoohoo">myLabel</Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
Bu yöntemi, web servis çağrıları için XML'e serileştirilmiş derin bir sınıf hiyerarşisiyle yeni bir projede başarıyla kullandım. Microsoft'un belgeleri, bir XmlSerializerNamespaces
kez oluşturduktan sonra herkes tarafından erişilebilen üye ile ne yapılacağı konusunda çok net değil ve pek çoğu bunun faydasız olduğunu düşünüyor. Ancak belgelerini izleyerek ve yukarıda gösterilen şekilde kullanarak, XmlSerializer'ın desteklenmeyen davranışa başvurmadan veya uygulayarak "kendi serileştirmenizi yuvarlayarak" sınıflarınız için XML üretme şeklini özelleştirebilirsiniz IXmlSerializable
.
Umarım bu yanıt, .tarafından oluşturulan standartlardan xsi
ve xsd
ad alanlarından nasıl kurtulacağımızı bir kez ve sonsuza kadar dinlendirir XmlSerializer
.
GÜNCELLEME: OP'nin tüm ad alanlarını kaldırmayla ilgili sorusunu yanıtladığımdan emin olmak istiyorum. Yukarıdaki kodum bunun için çalışacak; size nasıl olduğunu göstereyim. Şimdi, yukarıdaki örnekte, gerçekten tüm ad alanlarından kurtulamazsınız (çünkü kullanımda iki ad alanı vardır). XML belgenizin bir yerinde, buna benzer bir şeye ihtiyacınız olacak xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo
. Örnekteki sınıf daha büyük bir belgenin parçasıysa, o zaman bir ad alanının üzerinde bir yerde, biri (veya her ikisi için) Abracadbra
ve Whoohoo
. Değilse, ad alanlarının biri veya her ikisindeki öğe bir tür önekle dekore edilmelidir (iki varsayılan ad alanınız olamaz, değil mi?). Dolayısıyla, bu örnek Abracadabra
için varsayılan ad alanıdır. MyTypeWithNamespaces
Sınıfımın içine ad alanı için şu şekilde bir ad alanı öneki ekleyebilirim Whoohoo
:
public MyTypeWithNamespaces
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
new XmlQualifiedName(string.Empty, "urn:Abracadabra"), // Default Namespace
new XmlQualifiedName("w", "urn:Whoohoo")
});
}
Şimdi, sınıf tanımımda, <Label/>
öğenin ad alanında olduğunu belirttim "urn:Whoohoo"
, bu nedenle daha fazla bir şey yapmam gerekmiyor. Şimdi yukarıdaki serileştirme kodumu değiştirmeden kullanarak sınıfı serileştirdiğimde, bu çıktı:
<MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
<w:Label>myLabel</w:Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
Çünkü <Label>
belgenin geri kalanından farklı bir ad alanında, bu, someway, bir ad ile "dekore" olmalıdır. Hiçbir hala var olduğunu Bildirimi xsi
ve xsd
ad.
Bu, diğer soruya verdiğim cevabı bitiriyor. Ancak OP'nin ad alanı kullanmama konusundaki sorusunu yanıtladığımdan emin olmak istedim, çünkü bunu henüz tam olarak ele almadığımı hissediyorum. Bunun <Label>
belgenin geri kalanıyla aynı ad alanının parçası olduğunu varsayalım, bu durumda urn:Abracadabra
:
<MyTypeWithNamespaces>
<Label>myLabel<Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
Oluşturucunuz, varsayılan ad alanını almak için public özelliğiyle birlikte ilk kod örneğimde göründüğü gibi görünecektir:
// 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;
Daha sonra, MyTypeWithNamespaces
nesneyi serileştirmek için kullanan kodunuzda, yukarıda yaptığım gibi onu çağırırsınız:
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);
Ve XmlSerializer
çıktıda hiçbir ek ad alanı olmadan hemen yukarıda gösterildiği gibi aynı XML'i geri verir:
<MyTypeWithNamespaces>
<Label>myLabel<Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>