避免C ++程序的冗余映射

时间:2015-04-20 10:54:07

标签: c++ xml c++11 xml-parsing

这是我的C ++代码,用于执行以下操作:

  1. 比较一组XML文件,看看它们之间有什么不同
  2. 如果节点是新节点(在B.xml但不是A.xml中),则转出节点
  3. 扫描该节点并使用地图
  4. 将标签与信息类型相关联
  5. 根据数据的类型
  6. 处理数据

    我对步骤1-2如何工作非常满意,但是我觉得我可能执行得很差。我主要担心的是,我必须映射标签,即使已经匹配,例如id,当真正定义地图时,如果它不同,例如描述,那么它就是好的。

    我的代码:

    #include "pugi/pugixml.hpp"
    
    #include <iostream>
    #include <string>
    #include <map>
    
    int main()
     {
        // This map relates the type of content to the tag name in the XML file
        const std::map<std::string, std::string> tagMap {
             {"id", "id"}, {"description", "content"}, {"url", "web_address"}, {"location", "location"}
         };
    
        pugi::xml_document doca, docb;
         std::map<std::string, pugi::xml_node> mapa, mapb;
    
        for (auto& node: doca.child("data").children("entry")) {
         const char* id = node.child_value("id");
         mapa[id] = node;
         }
    
        for (auto& node: docb.child("data").children("entry")) {
         const char* idcs = node.child_value("id");
             if (!mapa.erase(idcs)) {
             mapb[idcs] = node;
             }
         }
    
        // For added nodes
         for (auto& eb: mapb) {
             // Loop through Tag map to see if we can find tags named "id, content, web_address or location" in the node returned
             for (auto& kv : tagMap) {
             // For each result, assign the value of that tag to the type of content
             // For example: description = Testing!
             kv.first = eb.second.child_value(kv.second.c_str());
             // If it's an ID...
                 if (kv.first == "id") {
                 // Do work on ID value (i.e check if it's unique)
                 }
                 if (kv.first == "description") {
                // Do work on Description data (I.e Trim it)
                 }
                 if (kv.first == "url") {
                 // Do work on URL data (I.e validate it)
                 }
                 if (kv.first == "location") {
                 // Do work on location data
                 }
             }
         }
    
    }
    

    示例输入文件:

    <data>
        <entry>
            <id>1</id>
            <content>Description</content>
            <web_address>www.google.com</web_address>
            <location>England</location>
            <unrelated>Test</unrelated>
            <not_needed>Test</not_needed>
        </entry>
    ..
    </data>
    

1 个答案:

答案 0 :(得分:1)

我对第3点和第4点有两个不同的改进:

  1. 简单改进:
  2. 作为tagMap的密钥使用枚举,例如

    enum Tags { Tag_ID, Tag_Description, ... }
    

    这避免了字符串比较。

    1. 更动态的方法是使用多态。
    2. 定义一个抽象的基类Tag

      class Tag {
      public:
          virtual const char* getTagname() const = 0;
          virtual void processNode(const std::string& value) = 0;
      };
      

      然后为您拥有的每个标记实现一个子类。

      class IdTag : public Tag {
      public:
          const char* getTagname() const { return "Id"; }
          void processNode(const std::string& value) { /* Do something */ }
      };
      

      现在您可以使用标签列表。 std::list<std::unique_ptr<Tag>> tagMap { new IdTag(), new DescriptionTag(), ... };

      你的新循环:

      // For added nodes
       for (auto& eb: mapb) {
           // Loop through Tag map to see if we can find tags named "id, content, web_address or location" in the node returned
           for (auto& kv : tagMap) {
               kv->processNode(eb.second.child_value(kv->getTagname());
           }
       }