使用xml加载对象。哪种方法最好?

时间:2009-11-05 01:30:48

标签: c++ xml design-patterns xml-serialization

TinyXML的

我有一个XML文件,它保存了一堆加载到对象中的数据。现在,我有一个巨大的方法来解析XML文件并根据XML文件的内容创建适当的对象。这个函数非常大,并导入了许多类定义。

每个类类型从XML进行自己的加载会更好吗?这样,XML代码分散在我的文件中,而不是一个位置。问题是我需要将XML函数应该读取的XML文件中的确切节点传递给它。这可行吗?我正在使用tinyxml,所以如果想象每个类都可以传递XML流(实际上是一个包含XML数据的数组)然后我也会传递该对象的根元素\ images \ fractal \ traversal \所以它知道它是什么应该是读书。

然后保存将以相同的方式工作。

哪种方法最好,使用更广泛?

3 个答案:

答案 0 :(得分:0)

我对TinyXML一无所知,但我已经使用libxml2这种类设计已经好几年了,而且它对我来说一直很好。

答案 1 :(得分:0)

序列化函数应该是它们序列化的类的朋友。如果要序列化和反序列化为XML,则应编写执行此功能的friend函数。您甚至可以编写执行此操作的自定义ostream & operator <<()函数,但如果要聚合对象,则会出现问题。更好的策略是定义一种机制,将单个对象转换为DOM文档中的Node。

答案 2 :(得分:0)

我可以想到一种方法,基于工厂提供基于标签的对象。

这里的困难并不是如何解耦每个对象内容的反序列化,而是解耦标记和对象的关联。

例如,假设您有以下XML

<my_xml>
  <bird> ... </bird>
</my_xml>

您如何知道应使用Bird标记的内容构建<bird>对象?

有两种方法:

  1. 1对1映射,ig:<my_xml>表示单个对象,因此知道如何反序列化自身。
  2. 集合:<my_xml>只不过是一个松散的对象集合
  3. 第一个很明显,你知道会发生什么,并且可以使用常规构造函数。

    C ++中的问题是你有静态类型,这使得第二种情况更加困难,因为你需要虚拟构造。

    虽然可以使用原型来实现虚拟构建。

     // Base class
     class Serializable:
     {
     public:
       virtual std::auto_ptr<XmlNode*> serialize() const = 0;
       virtual std::auto_ptr<Serializable> deserialize(const XmlNode&) const = 0;
     };
    
     // Collection of prototypes
     class Deserializer:
     {
     public:
       static void Register(Tag tag, const Serializable* item)
       {
         GetMap()[tag] = item;
       }
    
       std::auto_ptr<Serializable> Create(const XmlNode& node)
       {
         return GetConstMap()[node.tag()]->deserialize(node);
         // I wish I could write that ;)
       }
    
     private:
       typedef std::map<Tag, const Serializable*> prototypes_t;
    
       prototypes_t& GetMap()
       {
         static prototypes_t _Map;
         return _Map;
       }
    
       prototypes_t const& GetConstMap() { return GetMap(); }
     };
    
     // Example
     class Bird: public Serializable
     {
       virtual std::auto_ptr<Bird> deserialize(const XmlNode& node);
     };
    
     // In some cpp (bird.cpp is indicated)
     const Bird myBirdPrototype;
     Deserializer::Register('bird', myBirdPrototype);
    

    反序列化在C ++中总是有点混乱,动态类型确实有助于:)

    注意:它也适用于流媒体,但安全地安装起来有点复杂。流式传输的问题是你应该确保不要读取过去的数据并读取所有数据,以便流对于下一个对象处于“良好”状态:)