Jak serializować obiekt do XML bez pobierania xmlns = „…”?


109

Czy istnieje sposób na serializowanie obiektu w .NET bez automatycznej serializacji przestrzeni nazw XML? Wygląda na to, że domyślnie .NET uważa, że ​​obszary nazw XSI i XSD powinny być uwzględnione, ale nie chcę ich tam.

Odpowiedzi:


142

Ahh ... nieważne. Zawsze szukanie po zadaniu pytania daje odpowiedź. Mój obiekt, który jest serializowany, jest obji został już zdefiniowany. Dodanie XMLSerializerNamespace z pojedynczą pustą przestrzenią nazw do kolekcji załatwia sprawę.

W VB w ten sposób:

Dim xs As New XmlSerializer(GetType(cEmploymentDetail))
Dim ns As New XmlSerializerNamespaces()
ns.Add("", "")

Dim settings As New XmlWriterSettings()
settings.OmitXmlDeclaration = True

Using ms As New MemoryStream(), _
    sw As XmlWriter = XmlWriter.Create(ms, settings), _
    sr As New StreamReader(ms)
xs.Serialize(sw, obj, ns)
ms.Position = 0
Console.WriteLine(sr.ReadToEnd())
End Using

w C # w ten sposób:

//Create our own namespaces for the output
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

//Add an empty namespace and empty value
ns.Add("", "");

//Create the serializer
XmlSerializer slz = new XmlSerializer(someType);

//Serialize the object with our own namespaces (notice the overload)
slz.Serialize(myXmlTextWriter, someObject, ns);

12
Próbowałem tego w VB, atrybuty xsi i xsd zniknęły, ale pojawiły się atrybuty takie jak xmlns: q12 =, d3p1: type i xmlns: d3p1.
MiddleKay,

16
Wypróbowałem wersję C # i usunąłem xsi i xsd, ale dodałem prefiks q1: do wszystkich nazw tagów XML, których nie chciałem. Wygląda na to, że przykład C # jest niekompletny, odwołując się do myXmlTextWriter, który, jak zakładam, musi zostać zainicjowany w taki sam sposób, jak przykład VB.
czworościan

1
@redtetrahedron Czy znalazłeś sposób na pozbycie się tego q1gówna?
zmiażdżyć

Zapoznaj się z odpowiedzią stackoverflow.com/questions/31946240/… , jeśli q1 został dodany jako pusta przestrzeń nazw
aniruddha

20

Jeśli chcesz pozbyć się tego dodatkowego xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"i xmlns:xsd="http://www.w3.org/2001/XMLSchema"zachować własną przestrzeń nazw xmlns="http://schemas.YourCompany.com/YourSchema/", używasz tego samego kodu co powyżej, z wyjątkiem tej prostej zmiany:

//  Add lib namespace with empty prefix  
ns.Add("", "http://schemas.YourCompany.com/YourSchema/");   

13

Jeśli chcesz usunąć przestrzeń nazw, możesz również usunąć wersję, aby zaoszczędzić na wyszukiwaniu, dodałem tę funkcjonalność, więc poniższy kod będzie spełniał obie te funkcje.

Zapakowałem to również w ogólną metodę, ponieważ tworzę bardzo duże pliki xml, które są zbyt duże, aby można je było serializować w pamięci, więc zepsułem mój plik wyjściowy i serializuję go w mniejszych „kawałkach”:

    public static string XmlSerialize<T>(T entity) where T : class
    {
        // removes version
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;

        XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
        using (StringWriter sw = new StringWriter())
        using (XmlWriter writer = XmlWriter.Create(sw, settings))
        {
            // removes namespace
            var xmlns = new XmlSerializerNamespaces();
            xmlns.Add(string.Empty, string.Empty);

            xsSubmit.Serialize(writer, entity, xmlns);
            return sw.ToString(); // Your XML
        }
    }

Uwaga, StringWriterdomyślnie kodowanie UTF-16 może prowadzić do problemów z deserializacją. using (var reader = XmlReader.Create(stream)){ reader.Read(); }Powoduje to zgłoszenie wyjątku, ponieważ deklaracja stwierdza, że ​​jest to UTF-16, podczas gdy zawartość została faktycznie zapisana jako UTF-8. System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
Tyler StandishMan

Aby obejść ten problem i nadal używać XmlReader, możesz użyć opcji var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);Prawda użyje zestawienia komponentów, jeśli zostanie znaleziony, w przeciwnym razie wartość domyślna, którą podasz.
Tyler StandishMan

9

Proponuję tę klasę pomocniczą:

public static class Xml
{
    #region Fields

    private static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings {OmitXmlDeclaration = true, Indent = true};
    private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")});

    #endregion

    #region Methods

    public static string Serialize(object obj)
    {
        if (obj == null)
        {
            return null;
        }

        return DoSerialize(obj);
    }

    private static string DoSerialize(object obj)
    {
        using (var ms = new MemoryStream())
        using (var writer = XmlWriter.Create(ms, WriterSettings))
        {
            var serializer = new XmlSerializer(obj.GetType());
            serializer.Serialize(writer, obj, Namespaces);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }

    public static T Deserialize<T>(string data)
        where T : class
    {
        if (string.IsNullOrEmpty(data))
        {
            return null;
        }

        return DoDeserialize<T>(data);
    }

    private static T DoDeserialize<T>(string data) where T : class
    {
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
        {
            var serializer = new XmlSerializer(typeof (T));
            return (T) serializer.Deserialize(ms);
        }
    }

    #endregion
}

:)


świetna odpowiedź :) dodałem również ten strumień linii. Pozycja = 0; i
zwróciłem

Samo dodanie argumentu przestrzeni nazw do wywołania serializatora pomogło mi usunąć domyślne przestrzenie nazw. Moim zdaniem pisanie new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty})zamiast pisania new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})jest celowo jaśniejszym sposobem kodowania.
Suncat2000

5

Jeśli nie możesz pozbyć się dodatkowych atrybutów xmlns dla każdego elementu, podczas serializacji do xml z wygenerowanych klas (np .: gdy został użyty xsd.exe ), to masz coś takiego:

<manyElementWith xmlns="urn:names:specification:schema:xsd:one" />

następnie podzielę się z tobą tym, co zadziałało dla mnie (mieszanka poprzednich odpowiedzi i tego, co tutaj znalazłem )

jawnie ustaw wszystkie swoje różne xmlns w następujący sposób:

Dim xmlns = New XmlSerializerNamespaces()
xmlns.Add("one", "urn:names:specification:schema:xsd:one")
xmlns.Add("two",  "urn:names:specification:schema:xsd:two")
xmlns.Add("three",  "urn:names:specification:schema:xsd:three")

następnie przekaż go do serializacji

serializer.Serialize(writer, object, xmlns);

będziesz mieć trzy przestrzenie nazw zadeklarowane w elemencie głównym i nie będzie już konieczne ich generowanie w innych elementach, które zostaną odpowiednio poprzedzone

<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
   <one:Element />
   <two:ElementFromAnotherNameSpace /> ...

0
        XmlWriterSettings settings = new XmlWriterSettings
        {
            OmitXmlDeclaration = true
        };

        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");

        StringBuilder sb = new StringBuilder();

        XmlSerializer xs = new XmlSerializer(typeof(BankingDetails));

        using (XmlWriter xw = XmlWriter.Create(sb, settings))
        {
            xs.Serialize(xw, model, ns);
            xw.Flush();
            return sb.ToString();
        }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.