代码之家  ›  专栏  ›  技术社区  ›  BlueChippy

停止DataContractSerializer放入命名空间?

  •  5
  • BlueChippy  · 技术社区  · 15 年前

    代码如下所示:

    StringBuilder builder = new StringBuilder();
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.OmitXmlDeclaration = true;
    using (XmlWriter xmlWriter = XmlWriter.Create(builder, settings))
    {
        XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
        s.Serialize(xmlWriter, objectToSerialize);
    }
    

    <message xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
        xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 
        xmlns="urn:something">
     ...
    </message>
    

    要删除xsi和xsd名称空间,我可以按照 How to serialize an object to XML without getting xmlns=”…”? .

    我要我的消息标签为 <message> (没有任何命名空间属性)。我该怎么做?

    1 回复  |  直到 8 年前
        1
  •  239
  •   Thomas Levesque    16 年前
    ...
    XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    ns.Add("","");
    s.Serialize(xmlWriter, objectToSerialize, ns);
    
        2
  •  28
  •   Cheeso    16 年前

    这是两个答案中的第二个。

    如果您想在序列化过程中任意地从文档中剥离所有名称空间,可以通过实现自己的XmlWriter来实现。

    最简单的方法是从XmlTextWriter派生并重写发出名称空间的StartElement方法。当发出任何元素(包括根元素)时,XmlSerializer将调用StartElement方法。通过覆盖每个元素的名称空间,并用空字符串替换它,您已经从输出中剥离了名称空间。

    public class NoNamespaceXmlWriter : XmlTextWriter
    {
        //Provide as many contructors as you need
        public NoNamespaceXmlWriter(System.IO.TextWriter output)
            : base(output) { Formatting= System.Xml.Formatting.Indented;}
    
        public override void WriteStartDocument () { }
    
        public override void WriteStartElement(string prefix, string localName, string ns)
        {
            base.WriteStartElement("", localName, "");
        }
    }
    

    假设这是一种类型:

    // explicitly specify a namespace for this type,
    // to be used during XML serialization.
    [XmlRoot(Namespace="urn:Abracadabra")]
    public class MyTypeWithNamespaces
    {
        // private fields backing the properties
        private int _Epoch;
        private string _Label;
    
        // explicitly define a distinct namespace for this element
        [XmlElement(Namespace="urn:Whoohoo")]
        public string Label
        {
            set {  _Label= value; } 
            get { return _Label; } 
        }
    
        // this property will be implicitly serialized to XML using the
        // member name for the element name, and inheriting the namespace from
        // the type.
        public int Epoch
        {
            set {  _Epoch= value; } 
            get { return _Epoch; } 
        }
    }
    

    下面是在序列化过程中如何使用这样的东西:

            var o2= new MyTypeWithNamespaces { ..intializers.. };
            var builder = new System.Text.StringBuilder();
            using ( XmlWriter writer = new NoNamespaceXmlWriter(new System.IO.StringWriter(builder)))
            {
                s2.Serialize(writer, o2, ns2);
            }            
            Console.WriteLine("{0}",builder.ToString());
    

    但是XmlTextWriter有点坏了。根据 reference doc

    • 属性和元素名称中的字符无效。

    • 编码时,XmlTextWriter不会 角色实体。

    • 重复属性。

    • DOCTYPE public中的字符 标识符或系统标识符。

    XmlTextWriter的这些问题从.NETFramework的v1.1开始就一直存在,而且为了向后兼容,这些问题将一直存在。如果您不担心这些问题,那么请务必使用XmlTextWriter。但大多数人希望更可靠一点。

    XmlWriter 以及它的24种方法。

    例如:

    public class XmlWriterWrapper : XmlWriter
    {
        protected XmlWriter writer;
    
        public XmlWriterWrapper(XmlWriter baseWriter)
        {
            this.Writer = baseWriter;
        }
    
        public override void Close()
        {
            this.writer.Close();
        }
    
        protected override void Dispose(bool disposing)
        {
            ((IDisposable) this.writer).Dispose();
        }
    
        public override void Flush()
        {
            this.writer.Flush();
        }
    
        public override string LookupPrefix(string ns)
        {
            return this.writer.LookupPrefix(ns);
        }
    
        public override void WriteBase64(byte[] buffer, int index, int count)
        {
            this.writer.WriteBase64(buffer, index, count);
        }
    
        public override void WriteCData(string text)
        {
            this.writer.WriteCData(text);
        }
    
        public override void WriteCharEntity(char ch)
        {
            this.writer.WriteCharEntity(ch);
        }
    
        public override void WriteChars(char[] buffer, int index, int count)
        {
            this.writer.WriteChars(buffer, index, count);
        }
    
        public override void WriteComment(string text)
        {
            this.writer.WriteComment(text);
        }
    
        public override void WriteDocType(string name, string pubid, string sysid, string subset)
        {
            this.writer.WriteDocType(name, pubid, sysid, subset);
        }
    
        public override void WriteEndAttribute()
        {
            this.writer.WriteEndAttribute();
        }
    
        public override void WriteEndDocument()
        {
            this.writer.WriteEndDocument();
        }
    
        public override void WriteEndElement()
        {
            this.writer.WriteEndElement();
        }
    
        public override void WriteEntityRef(string name)
        {
            this.writer.WriteEntityRef(name);
        }
    
        public override void WriteFullEndElement()
        {
            this.writer.WriteFullEndElement();
        }
    
        public override void WriteProcessingInstruction(string name, string text)
        {
            this.writer.WriteProcessingInstruction(name, text);
        }
    
        public override void WriteRaw(string data)
        {
            this.writer.WriteRaw(data);
        }
    
        public override void WriteRaw(char[] buffer, int index, int count)
        {
            this.writer.WriteRaw(buffer, index, count);
        }
    
        public override void WriteStartAttribute(string prefix, string localName, string ns)
        {
            this.writer.WriteStartAttribute(prefix, localName, ns);
        }
    
        public override void WriteStartDocument()
        {
            this.writer.WriteStartDocument();
        }
    
        public override void WriteStartDocument(bool standalone)
        {
            this.writer.WriteStartDocument(standalone);
        }
    
        public override void WriteStartElement(string prefix, string localName, string ns)
        {
            this.writer.WriteStartElement(prefix, localName, ns);
        }
    
        public override void WriteString(string text)
        {
            this.writer.WriteString(text);
        }
    
        public override void WriteSurrogateCharEntity(char lowChar, char highChar)
        {
            this.writer.WriteSurrogateCharEntity(lowChar, highChar);
        }
    
        public override void WriteValue(bool value)
        {
            this.writer.WriteValue(value);
        }
    
        public override void WriteValue(DateTime value)
        {
            this.writer.WriteValue(value);
        }
    
        public override void WriteValue(decimal value)
        {
            this.writer.WriteValue(value);
        }
    
        public override void WriteValue(double value)
        {
            this.writer.WriteValue(value);
        }
    
        public override void WriteValue(int value)
        {
            this.writer.WriteValue(value);
        }
    
        public override void WriteValue(long value)
        {
            this.writer.WriteValue(value);
        }
    
        public override void WriteValue(object value)
        {
            this.writer.WriteValue(value);
        }
    
        public override void WriteValue(float value)
        {
            this.writer.WriteValue(value);
        }
    
        public override void WriteValue(string value)
        {
            this.writer.WriteValue(value);
        }
    
        public override void WriteWhitespace(string ws)
        {
            this.writer.WriteWhitespace(ws);
        }
    
    
        public override XmlWriterSettings Settings
        {
            get
            {
                return this.writer.Settings;
            }
        }
    
        protected XmlWriter Writer
        {
            get
            {
                return this.writer;
            }
            set
            {
                this.writer = value;
            }
        }
    
        public override System.Xml.WriteState WriteState
        {
            get
            {
                return this.writer.WriteState;
            }
        }
    
        public override string XmlLang
        {
            get
            {
                return this.writer.XmlLang;
            }
        }
    
        public override System.Xml.XmlSpace XmlSpace
        {
            get
            {
                return this.writer.XmlSpace;
            }
        }        
    }
    

    然后,像前面一样,提供一个重写StartElement方法的派生类:

    public class NamespaceSupressingXmlWriter : XmlWriterWrapper
    {
        //Provide as many contructors as you need
        public NamespaceSupressingXmlWriter(System.IO.TextWriter output)
            : base(XmlWriter.Create(output)) { }
    
        public NamespaceSupressingXmlWriter(XmlWriter output)
            : base(XmlWriter.Create(output)) { }
    
        public override void WriteStartElement(string prefix, string localName, string ns)
        {
            base.WriteStartElement("", localName, "");
        }
    }
    

    然后像这样使用这个书写器:

            var o2= new MyTypeWithNamespaces { ..intializers.. };
            var builder = new System.Text.StringBuilder();
            var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
            using ( XmlWriter innerWriter = XmlWriter.Create(builder, settings))
                using ( XmlWriter writer = new NamespaceSupressingXmlWriter(innerWriter))
                {
                    s2.Serialize(writer, o2, ns2);
                }            
            Console.WriteLine("{0}",builder.ToString());
    

    Oleg Tkachenko .

        3
  •  16
  •   rmtheis sillygoose    10 年前

    在阅读了微软的文档和一些在线解决方案之后,我发现了这个问题的解决方案。它与内置 XmlSerializer 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以用于web服务调用。微软的文档并不是很清楚如何处理公共访问 XmlSerializerNamespaces IXmlSerializable .

    xsi xsd XmlSerializer .

    更新:我只是想确保我回答了OP关于删除所有名称空间的问题。我上面的代码将用于此;让我演示如何。现在,在上面的示例中,您真的无法摆脱所有名称空间(因为有两个名称空间正在使用)。在XML文档的某个地方,您需要 xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo . 如果示例中的类是较大文档的一部分,则必须为其中一个(或两者)声明命名空间上方的某处 Abracadbra Whoohoo Abracadabra 是defalt命名空间。我可以在我的房间里 MyTypeWithNamespaces 类为 屋虎

    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> 南印第安湖 xsd公司 名称空间。

        4
  •  7
  •   Tejas    9 年前
    XmlSerializer sr = new XmlSerializer(objectToSerialize.GetType());
    TextWriter xmlWriter = new StreamWriter(filename);
    XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
    namespaces.Add(string.Empty, string.Empty);
    sr.Serialize(xmlWriter, objectToSerialize, namespaces);
    
        5
  •  6
  •   Cheeso    16 年前

    如果您希望对名称空间进行良好的控制—例如,如果您希望省略其中的一些名称空间而不是其他名称空间,或者如果您希望用另一个名称空间替换一个名称空间,那么可以使用 XmlAttributeOverrides .

    假设您有以下类型定义:

    // explicitly specify a namespace for this type,
    // to be used during XML serialization.
    [XmlRoot(Namespace="urn:Abracadabra")]
    public class MyTypeWithNamespaces
    {
        // private fields backing the properties
        private int _Epoch;
        private string _Label;
    
        // explicitly define a distinct namespace for this element
        [XmlElement(Namespace="urn:Whoohoo")]
        public string Label
        {
            set {  _Label= value; } 
            get { return _Label; } 
        }
    
        // this property will be implicitly serialized to XML using the
        // member name for the element name, and inheriting the namespace from
        // the type.
        public int Epoch
        {
            set {  _Epoch= value; } 
            get { return _Epoch; } 
        }
    }
    

            var o2= new MyTypeWithNamespaces() { ..initializers...};
            ns.Add( "", "urn:Abracadabra" );
            XmlSerializer s2 = new XmlSerializer(typeof(MyTypeWithNamespaces));
            s2.Serialize(System.Console.Out, o2, ns);
    

    您将得到如下XML:

    <MyTypeWithNamespaces xmlns="urn:Abracadabra">
      <Label xmlns="urn:Whoohoo">Cimsswybclaeqjh</Label>
      <Epoch>97</Epoch>
    </MyTypeWithNamespaces>
    

    注意,根元素上有一个默认名称空间,而“Label”元素上也有一个不同的名称空间。在上面的代码中,这些名称空间是由修饰类型的属性指定的。

    NET中的Xml序列化框架包括显式 覆盖

            // instantiate the container for all attribute overrides
            XmlAttributeOverrides xOver = new XmlAttributeOverrides();
    
            // define a set of XML attributes to apply to the root element
            XmlAttributes xAttrs1 = new XmlAttributes();
    
            // define an XmlRoot element (as if [XmlRoot] had decorated the type)
            // The namespace in the attribute override is the empty string. 
            XmlRootAttribute xRoot = new XmlRootAttribute() { Namespace = ""};
    
            // add that XmlRoot element to the container of attributes
            xAttrs1.XmlRoot= xRoot;
    
            // add that bunch of attributes to the container holding all overrides
            xOver.Add(typeof(MyTypeWithNamespaces), xAttrs1);
    
            // create another set of XML Attributes
            XmlAttributes xAttrs2 = new XmlAttributes();
    
            // define an XmlElement attribute, for a type of "String", with no namespace
            var xElt = new XmlElementAttribute(typeof(String)) { Namespace = ""};
    
            // add that XmlElement attribute to the 2nd bunch of attributes
            xAttrs2.XmlElements.Add(xElt);
    
            // add that bunch of attributes to the container for the type, and
            // specifically apply that bunch to the "Label" property on the type.
            xOver.Add(typeof(MyTypeWithNamespaces), "Label", xAttrs2);
    
            // instantiate a serializer with the overrides 
            XmlSerializer s3 = new XmlSerializer(typeof(MyTypeWithNamespaces), xOver);
    
            // serialize
            s3.Serialize(System.Console.Out, o2, ns2);
    

    结果是这样的;

    <MyTypeWithNamespaces>
      <Label>Cimsswybclaeqjh</Label>
      <Epoch>97</Epoch>
    </MyTypeWithNamespaces>
    

    你已经剥离了名称空间。

    一个合乎逻辑的问题是, 在序列化过程中,是否可以从任意类型中剥离所有名称空间,而不必进行显式重写? 答案是肯定的,如何做到这一点是在我的下一个回应。

    推荐文章