Ponieważ Dave poprosił mnie o powtórzenie mojej odpowiedzi na temat Pomijania wszystkich przestrzeni nazw xsi i xsd podczas serializacji obiektu w .NET , zaktualizowałem ten post i powtórzyłem moją odpowiedź tutaj z wyżej wymienionego łącza. Przykład użyty w tej odpowiedzi jest tym samym przykładem zastosowanym w przypadku innego pytania. Poniższy tekst jest kopiowany dosłownie.
Po przeczytaniu dokumentacji Microsoftu i kilku rozwiązań online, znalazłem rozwiązanie tego problemu. Działa z wbudowaną XmlSerializer
i niestandardową serializacją XML za pośrednictwem IXmlSerialiazble
.
Na marginesie użyję tego samego MyTypeWithNamespaces
przykładu XML, który został użyty w odpowiedziach na to pytanie.
[XmlRoot("MyTypeWithNamespaces", Namespace="urn:Abracadabra", IsNullable=false)]
public class MyTypeWithNamespaces
{
public MyTypeWithNamespaces( )
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
new XmlQualifiedName(string.Empty, "urn:Abracadabra")
});
}
public MyTypeWithNamespaces(string label, int epoch) : this( )
{
this._label = label;
this._epoch = epoch;
}
[XmlElement(Namespace="urn:Whoohoo")]
public string Label
{
get { return this._label; }
set { this._label = value; }
}
private string _label;
public int Epoch
{
get { return this._epoch; }
set { this._epoch = value; }
}
private int _epoch;
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
get { return this._namespaces; }
}
private XmlSerializerNamespaces _namespaces;
}
To wszystko do tej klasy. Niektórzy sprzeciwiają się posiadaniu XmlSerializerNamespaces
obiektu gdzieś w swoich klasach; ale jak widać, schludnie schowałem go w domyślnym konstruktorze i ujawniłem właściwość publiczną, która zwraca przestrzenie nazw.
Teraz, gdy przyjdzie czas na serializację klasy, użyjesz następującego kodu:
MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });
MemoryStream ms = new MemoryStream();
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Encoding = Encoding.UTF8;
XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws);
xtw.Formatting = Formatting.Indented;
xs.Serialize(xtw, myType, myType.Namespaces);
Gdy to zrobisz, powinieneś otrzymać następujący wynik:
<MyTypeWithNamespaces>
<Label xmlns="urn:Whoohoo">myLabel</Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
Z powodzeniem zastosowałem tę metodę w niedawnym projekcie z głęboką hierarchią klas, które są serializowane do XML dla wywołań usług internetowych. Dokumentacja Microsoftu nie jest zbyt jasna, co zrobić z publicznie dostępnym XmlSerializerNamespaces
członkiem po utworzeniu, a tak wielu uważa, że jest bezużyteczna. Ale postępując zgodnie z ich dokumentacją i używając jej w sposób pokazany powyżej, możesz dostosować sposób, w jaki XmlSerializer generuje XML dla twoich klas bez uciekania się do nieobsługiwanego zachowania lub „toczenia własnej” serializacji przez implementację IXmlSerializable
.
Mam nadzieję, że ta odpowiedź raz na zawsze położy kres temu, jak pozbyć się standardu xsi
i xsd
przestrzeni nazw generowanych przez XmlSerializer
.
AKTUALIZACJA: Chcę się tylko upewnić, że odpowiedziałem na pytanie OP dotyczące usunięcia wszystkich przestrzeni nazw. Mój kod powyżej będzie działał w tym celu; Pokażę ci jak. Teraz, w powyższym przykładzie, naprawdę nie możesz pozbyć się wszystkich przestrzeni nazw (ponieważ są używane dwie przestrzenie nazw). Gdzieś w dokumencie XML będziesz potrzebować czegoś takiego jak xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo
. Jeśli klasa w przykładzie jest częścią większego dokumentu, to gdzieś powyżej przestrzeni nazw musi być zadeklarowana dla jednego z (lub obu) Abracadbra
i Whoohoo
. Jeśli nie, to element w jednej lub obu przestrzeniach nazw musi być ozdobiony jakimś prefiksem (nie możesz mieć dwóch domyślnych przestrzeni nazw, prawda?). W tym przykładzie Abracadabra
jest to domyślna przestrzeń nazw. Mógłbym wewnątrz mojej MyTypeWithNamespaces
klasy dodać prefiks przestrzeni nazw dla Whoohoo
przestrzeni nazw w następujący sposób:
public MyTypeWithNamespaces
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
new XmlQualifiedName(string.Empty, "urn:Abracadabra"),
new XmlQualifiedName("w", "urn:Whoohoo")
});
}
Teraz w mojej definicji klasy wskazałem, że <Label/>
element znajduje się w przestrzeni nazw "urn:Whoohoo"
, więc nie muszę nic więcej robić. Kiedy teraz serializuję klasę przy użyciu niezmienionego mojego powyższego kodu serializacji, jest to wynik:
<MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
<w:Label>myLabel</w:Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
Ponieważ <Label>
znajduje się w innej przestrzeni nazw niż reszta dokumentu, w jakiś sposób musi być „ozdobiony” przestrzenią nazw. Zauważ, że nadal nie ma przestrzeni nazw xsi
i xsd
.
To kończy moją odpowiedź na drugie pytanie. Ale chciałem się upewnić, że odpowiedziałem na pytanie OP dotyczące używania żadnych przestrzeni nazw, ponieważ czuję, że tak naprawdę jeszcze do tego nie odpowiedziałem. Załóżmy, że <Label>
jest to część tej samej przestrzeni nazw, co reszta dokumentu, w tym przypadku urn:Abracadabra
:
<MyTypeWithNamespaces>
<Label>myLabel<Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
Twój konstruktor wyglądałby tak, jak w moim pierwszym przykładzie kodu, wraz z właściwością publiczną do pobrania domyślnej przestrzeni nazw:
public MyTypeWithNamespaces( )
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
new XmlQualifiedName(string.Empty, "urn:Abracadabra")
});
}
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
get { return this._namespaces; }
}
private XmlSerializerNamespaces _namespaces;
Później w swoim kodzie, który używa MyTypeWithNamespaces
obiektu do serializacji, nazwałbyś to tak, jak zrobiłem powyżej:
MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });
...
xs.Serialize(xtw, myType, myType.Namespaces);
I XmlSerializer
wypluliby ten sam kod XML, który pokazano bezpośrednio powyżej, bez dodatkowych przestrzeni nazw w wyniku:
<MyTypeWithNamespaces>
<Label>myLabel<Label>
<Epoch>42</Epoch>
</MyTypeWithNamespaces>
XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws);
że musiałem wymienićvar xtw = XmlTextWriter.Create(memStm, xws);
.XmlTextWriter.Create
zwraca (abstrakcyjną?)XmlWriter
instancję. Więc @ Preza8 jest poprawne, straciłbyś możliwość ustawiania innychXmlTextWriter
specyficznych właściwości (przynajmniej nie bez rzucania go w dół), a więc konkretnego rzutowania naXmlTextWriter
.źródło
Istnieje alternatywa - można podać element członkowski typu XmlSerializerNamespaces w typie do serializacji. Udekoruj go atrybutem XmlNamespaceDeclarations . Dodaj prefiksy przestrzeni nazw i identyfikatory URI do tego elementu członkowskiego. Następnie każda serializacja, która nie zapewnia jawnie XmlSerializerNamespaces, użyje prefiksu przestrzeni nazw + par URI, które zostały wprowadzone do typu.
Przykładowy kod, załóżmy, że to Twój typ:
Możesz to zrobić:
A to oznacza, że każda serializacja tej instancji, która nie określa własnego zestawu par prefiks + URI, użyje przedrostka „p” dla przestrzeni nazw „urn: mycompany.2009”. Pominie również przestrzenie nazw xsi i xsd.
Różnica polega na tym, że dodajesz XmlSerializerNamespaces do samego typu, zamiast używać go jawnie w wywołaniu XmlSerializer.Serialize (). Oznacza to, że jeśli wystąpienie twojego typu jest serializowane przez kod, którego nie jesteś właścicielem (na przykład w stosie usług sieci Web), a ten kod nie zapewnia jawnie XmlSerializerNamespaces, ten serializator użyje przestrzeni nazw podanych w wystąpieniu.
źródło
Używam:
Aby uzyskać następujący kod XML:
<?xml version="1.0"?> <Person xmlns="http://www.something.org/schema"> <FirstName>Donald</FirstName> <LastName>Duck</LastName> </Person>
Jeśli nie potrzebujesz przestrzeni nazw, po prostu ustaw DEFAULT_NAMESPACE na „”.
źródło