进出 XPathDocument 的协议缓冲区消息

Posted

技术标签:

【中文标题】进出 XPathDocument 的协议缓冲区消息【英文标题】:protocol buffer message to and from an XPathDocument 【发布时间】:2011-06-24 12:25:22 【问题描述】:

我正在尝试序列化和反序列化与 XPathDocument 之间的协议缓冲区消息,但它失败并出现异常: ProtoBuf.ProtoException:在消息中检测到不匹配的组标签 我该如何完成这项工作?

我正在使用 protobuf-net,我的源代码重现它看起来像这样:

TestMsg.proto

    option optimize_for = SPEED;

//*************************
message Test 
    repeated A a = 1;


message A 
    required string str = 1;

程序.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using ProtoBuf;
using TestMsg;

namespace protocolbufferserialize

    class Program
    
        static void Main(string[] args)
        
            Test t = new Test();
            XPathDocument xmldoc = Serialize(t);
            Test t1 = Serialize(xmldoc);
        

        public static XPathDocument Serialize(Test wro)
        
            XPathDocument xmlDoc = null;
            Serializer.PrepareSerializer<Test>();

            XmlSerializer x = new XmlSerializer(wro.GetType());
            using (MemoryStream memoryStream = new MemoryStream())
            
                using (TextWriter w = new StreamWriter(memoryStream))
                
                    x.Serialize(w, wro);
                    memoryStream.Position = 0;
                    xmlDoc = new XPathDocument(memoryStream);
                
            
            return xmlDoc;
        

        public static Test Serialize(XPathDocument xmlDoc)
        
            Test t = null;
            Serializer.PrepareSerializer<Test>();

            XmlSerializer x = new XmlSerializer(xmlDoc.GetType());
            using (MemoryStream memoryStream = new MemoryStream())
            
                using (TextWriter w = new StreamWriter(memoryStream))
                
                    x.Serialize(w, xmlDoc);
                    memoryStream.Position = 0;
                    t = Serializer.Deserialize<Test>(memoryStream);
                
            
            return t;
        
    


我试图扩展使用Serializer.Merge,但是当它从xml返回时Test对象是空的。

    using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using ProtoBuf;
using TestMsg;

namespace TestXMLSerilizationLars

    class Program
    
        static void Main(string[] args)
        
            Test t = new Test();
            A a = new A();
            string str = "test";
            a.str = str;
            t.a.Add(a);
            XPathDocument xmldoc = Serialize(t);
            WriteXpathDocument(xmldoc, "c:\\testmsg.xml");
            Test t1 = Serialize(xmldoc);
        

        public static XPathDocument Serialize(Test t)
        
            XPathDocument xmlDoc = null;
            Serializer.PrepareSerializer<Test>();

            XmlSerializer x = new XmlSerializer(t.GetType());
            using (MemoryStream memoryStream = new MemoryStream())
            
                using (TextWriter w = new StreamWriter(memoryStream))
                
                    x.Serialize(w, t);
                    memoryStream.Position = 0;
                    xmlDoc = new XPathDocument(memoryStream);
                
            
            return xmlDoc;
        

        public static Test Serialize(XPathDocument xmlDoc)
        
            Test t = null;

            Type type = xmlDoc.GetType();

            XmlSerializer serializer = new XmlSerializer(type);

            using (MemoryStream memoryStream = new MemoryStream())
            
                serializer.Serialize(memoryStream, xmlDoc);
                // memoryStream.Close();
                Test newt = Deserialize(memoryStream.ToArray());
                return newt;
                        
            return t;
        

        static public Test Deserialize(byte[] Bytes)
        
            MemoryStream SerializeStream = new MemoryStream(Bytes);
            Test NewObject = Serializer.Deserialize<Test>(SerializeStream);
            Test ObjectExist = new Test();

            if (ObjectExist == null)
            
                return NewObject;
            
            else
            
                SerializeStream.Seek(0, SeekOrigin.Begin);
                Serializer.Merge<Test>(SerializeStream, ObjectExist);
                return ObjectExist;
            
        

        public static void WriteXpathDocument(XPathDocument xpathDoc, string filename)
        
            // Create XpathNaviagtor instances from XpathDoc instance.
            XPathNavigator objXPathNav = xpathDoc.CreateNavigator();

            // Create XmlWriter settings instance.
            XmlWriterSettings objXmlWriterSettings = new XmlWriterSettings();
            objXmlWriterSettings.Indent = true;

            // Create disposable XmlWriter and write XML to file.
            using (XmlWriter objXmlWriter = XmlWriter.Create(filename, objXmlWriterSettings))
            
                objXPathNav.WriteSubtree(objXmlWriter);
                objXmlWriter.Close();
            
        
    

我转出的xml文件是这样的

<?xml version="1.0" encoding="utf-8"?>
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <a>
    <A>
      <str>test</str>
    </A>
  </a>
</Test>

【问题讨论】:

【参考方案1】:

你在这里使用 protobuf 的唯一一次是:

x.Serialize(w, xmlDoc);
memoryStream.Position = 0;
t = Serializer.Deserialize<Test>(memoryStream);

您在哪里写入了 xml(xXmlSerializer),然后尝试通过 protobuf (Serializer.Deserialize) 读取它。

但是; protobuf 不是 xml;它是一种与 xml 无关的二进制格式完全。如果您打算深度克隆数据,您还应该使用 protobuf-net (Serializer.Serialize)序列化

通常可以在两种格式之间转换一个模型,但是流本身是不可交换的。

【讨论】:

以上是关于进出 XPathDocument 的协议缓冲区消息的主要内容,如果未能解决你的问题,请参考以下文章

确定协议缓冲区消息类型的最佳实践

协议缓冲区:更改字段名称会破坏消息吗?

如何使用协议缓冲区创建动态消息?

与 JSON 相比,作为协议缓冲区发送时消息的大小如何减小

google 的从 c# 到 java 的协议缓冲区 - 协议消息标签的线路类型无效

在协议缓冲区消息中存储二进制数据缓冲区