使用XmlDictionaryWriter.CreateBinaryWriter和XmlDictionary

时间:2016-02-08 13:59:18

标签: c# .net xml serialization binary-xml

我想以紧凑的格式将xml文档写入磁盘。为此,我使用了网络框架方法XmlDictionaryWriter.CreateBinaryWriter(Stream stream,IXmlDictionary dictionary)

此方法编写自定义紧凑二进制xml表示形式,稍后可由XmlDictionaryWriter.CreateBinaryReader读取。该方法接受可以包含公共字符串的XmlDictionary,以便每次都不必在输出中打印这些字符串。字典索引将打印在文件中,而不是字符串。 CreateBinaryReader稍后可以使用相同的字典来反转该过程。

然而,我通过的词典显然没有使用。请考虑以下代码:

using System.IO;
using System.Xml;
using System.Xml.Linq;

class Program
{
    public static void Main()
    {
        XmlDictionary dict = new XmlDictionary();
        dict.Add("myLongRoot");
        dict.Add("myLongAttribute");
        dict.Add("myLongValue");
        dict.Add("myLongChild");
        dict.Add("myLongText");

        XDocument xdoc = new XDocument();
        xdoc.Add(new XElement("myLongRoot",
                                new XAttribute("myLongAttribute", "myLongValue"),
                                new XElement("myLongChild", "myLongText"),
                                new XElement("myLongChild", "myLongText"),
                                new XElement("myLongChild", "myLongText")
                                ));

        using (Stream stream = File.Create("binaryXml.txt"))
        using (var writer = XmlDictionaryWriter.CreateBinaryWriter(stream, dict))
        {
            xdoc.WriteTo(writer);
        }
    }
}

生成的输出为此(二进制控制字符未显示)

@
myLongRootmyLongAttribute˜myLongValue@myLongChild™
myLongText@myLongChild™
myLongText@myLongChild™
myLongText

显然XmlDictionary尚未使用过。所有字符串都在输出中完整显示,甚至多次。

这不仅限于XDocument。在上面的最小例子中,我使用了一个XDocument来演示这个问题,但最初我在使用XmlDictionaryWriter和DataContractSerializer时偶然发现了这个问题,因为它是常用的。结果是一样的:

[Serializable]
public class myLongChild
{
    public double myLongText = 0;
}
...
using (Stream stream = File.Create("binaryXml.txt"))
using (var writer = XmlDictionaryWriter.CreateBinaryWriter(stream, dict))
{
    var dcs = new DataContractSerializer(typeof(myLongChild));
    dcs.WriteObject(writer, new myLongChild());
}

结果输出没有使用我的XmlDictionary。

如何让XmlDictionaryWriter使用上传的XmlDictionary?

或者我误解了它是如何工作的?

使用DataContractSerializer方法,我尝试调试网络框架代码( visual studio / options / debugging / enable net。framework source stepping )。显然,Writer会尝试按预期查找字典中的每个字符串。但是line 356 of XmlbinaryWriter.cs中的查找失败,原因我不清楚。

我考虑过的替代方案:

  • XmlDictionaryWriter.CreatebinaryWriter存在重载,它也接受XmlBinaryWriterSession。然后,编写器将它遇到的任何新字符串添加到会话字典中。但是,我只想使用静态字典进行读写,这是事先已知的

  • 我可以将整个事物包装成GzipStream并让压缩处理多个字符串实例。但是,这不会压缩每个字符串的第一个实例,而且整体上似乎是一种笨拙的解决方法。

1 个答案:

答案 0 :(得分:3)

是的,存在误解。 XmlDictionaryWriter主要用于对象的序列化,它是XmlWriter的子类。 XDocument.WriteTo(XmlWriter something)XmlWriter为参数。调用XmlDictionaryWriter.CreateBinaryWriter将在内部创建System.Xml.XmlBinaryNodeWriter的实例。这个类有两种方法用于"常规"写作:

// override of XmlWriter
public override void WriteStartElement(string prefix, string localName)
{
  // plain old "xml" for me please
}

以及基于字典的方法:

// override of XmlDictionaryWriter
public override void WriteStartElement(string prefix, XmlDictionaryString localName)
{
  // I will use dictionary to hash element names to get shorter output
}

如果您通过DataContractSerializer序列化对象,则主要使用后者(注意其方法WriteObject同时引用XmlDictionaryWriterXmlWriter类型的参数),而{{1}只需要XDocument

关于你的问题 - 如果我是你,我自己做XmlWriter

XmlWriter

更新(根据您的评论)

如果您确实使用class CustomXmlWriter : XmlWriter { private readonly XmlDictionaryWriter _writer; public CustomXmlWriter(XmlDictionaryWriter writer) { _writer = writer; } // override XmlWriter methods to use the dictionary-based approach instead } ,则代码中的错误很少。

1)POC类必须用DataContractSerializer[DataContract]属性进行修饰,序列化值应该是property而不是field;还将名称空间设置为空值,或者您也必须处理字典中的名称空间。像:

[DataMember]

2)也提供会话实例;对于null会话,字典编写器使用默认的(namespace XmlStuff { [DataContract(Namespace = "")] public class myLongChild { [DataMember] public double myLongText { get; set; } } [DataContract(Namespace = "")] public class myLongRoot { [DataMember] public IList<myLongChild> Items { get; set; } } } - )实现:

XmlWriter