mFAST fast_type_gen流程详解

来源:互联网 发布:公司数据库 编辑:程序博客网 时间:2024/06/17 22:20

先打开xml模板文件并将文件内容读入一个名为xml的string:

std::ifstream ifs(argv[i]);
std::string xml((std::istreambuf_iterator<char>(ifs)),                      std::istreambuf_iterator<char>());

获取不带扩展名的文件名filebase,以后作为namespace名:

path f(path(argv[i]).stem());   //boost 功能,只取文件名,不带路径和扩展名      std::string filebase = f.string();

根据xml的内容生成一个名为des的dynamic_templates_description对象:

mfast::dynamic_templates_description desc(xml.c_str(),                                                filebase.c_str(),                                                &registry);

dynamic_templates_description的构造函数如下,调用tinyxml2,创建一个XMLDoucument类的对象document用以解析xml内容。

dynamic_templates_description::dynamic_templates_description(const char*        xml_content,                                                               const char*        cpp_ns,                                                               template_registry* registry)  {    XMLDocument document;    if (document.Parse(xml_content) == 0) {      xml_parser::templates_builder builder(this, cpp_ns, registry);      document.Accept(&builder);    }    else {      BOOST_THROW_EXCEPTION(std::runtime_error("XML parse error"));    }  }

解析成功的话创建一个templates_builer类的对象builder用以初始化遍历document,该类继承自public XMLVisitor、boost::base_from_member和field_builder_base。Accept函数在tinyxml2中定义,对于不同的XML元素类型定义不同。对XMLDocument的定义如下,利用一对VisITEnter/VisitExit函数作为出入口。

bool XMLDocument::Accept( XMLVisitor* visitor ) const{    TIXMLASSERT( visitor );    if ( visitor->VisitEnter( *this ) ) {        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {            if ( !node->Accept( visitor ) ) {                break;            }        }    }    return visitor->VisitExit( *this );}

这里调用的应该是templates_builder的visit函数,定义如下。参数为XMLDocument的visitenter函数没有重载,直接返回TRUE。
然后调用参数为XMLElement的visitenter函数,代码如下。先获取element名称,如果是templates(xml文件根元素),则配置des的ns_、template_ns_和dictionary三个成员变量,然后返回TRUE,继续accept过程处理子节点。项目中templates节点的子节点为template,利用templates_builder和template元素创建field_builder类的对象builder,调用build函数,创建field。

bool    templates_builder::VisitEnter (const XMLElement & element, const XMLAttribute*)    {      const char* element_name = element.Name();      if (std::strcmp(element_name, "templates") == 0 ) {        definition_->ns_ = string_dup(get_optional_attr(element, "ns", ""), alloc());        resolved_ns_= string_dup(get_optional_attr(element, "templateNs", ""), alloc());        definition_->template_ns_ = resolved_ns_;        definition_->dictionary_ = string_dup(get_optional_attr(element, "dictionary", ""), alloc());        return true;      }      else if (strcmp(element_name, "define") == 0) {        const char* name =  get_optional_attr(element, "name", 0);        const XMLElement* elem = element.FirstChildElement();        if (name && elem) {          field_builder builder(this, *elem, name);          builder.build();        }      }      else if (strcmp(element_name, "template") == 0) {        field_builder builder(this, element);        builder.build();      }      else if (strcmp(element_name, "view") == 0) {        view_info_builder builder(alloc());        const group_field_instruction* inst = dynamic_cast<const group_field_instruction*>(this->find_type(                                                                                             get_optional_attr(element,"ns",        resolved_ns_),                                                                                             get_optional_attr(element,"reference", "")));        if (inst == 0)          BOOST_THROW_EXCEPTION(fast_static_error("Invalid view specification"));        definition_->view_infos_.push_back( builder.build(element, inst) );      }      return false;    }    bool    templates_builder::VisitExit (const XMLElement & element)    {      if (std::strcmp(element.Name(), "templates") == 0 ) {        typedef const template_instruction* const_template_instruction_ptr_t;        definition_->instructions_ = new (alloc())const_template_instruction_ptr_t[this->num_instructions()];        std::copy(templates_.begin(), templates_.end(), definition_->instructions_);        definition_->instructions_count_ = static_cast<uint32_t>(templates_.size());      }      return true;    }

field_builder的构造函数如下。第一个参数为field_builder_base类型的,调用的时候传入的为templates_builder,为其子类。

 field_builder::field_builder(field_builder_base* parent,                                 const XMLElement&   element)      : fast_xml_attributes(element.FirstAttribute())      , field_builder_base(parent->registry(),                           parent->local_types())      , element_(element)      , parent_(parent)    {    }

其基类fast_xml_attributes利用element(此处为template类型)的第一个attribute初始化,该基类的构造函数如下。可以看到,根据此attribute的类型,设置fast_xml_attributes的相应属性,本项目中一般为name属性。

fast_xml_attributes(const XMLAttribute* attr)      {        name_ = 0;        id_ = 0;        ns_ = 0;        templateNs_ = 0;        dictionary_ = 0;        presence_ = 0;        charset_ = 0;        tag_ = 0;        decimal_place_ = 0;        set(attr);      }      void set(const XMLAttribute* attr)      {        while (attr != 0) {          const char* name = attr->Name();          if (std::strcmp(name, "name") == 0)            name_ = attr->Value();          else if (std::strcmp(name, "ns") == 0)            ns_ = attr->Value();          else if (std::strcmp(name, "templateNs") == 0)            templateNs_ = attr->Value();          else if (std::strcmp(name, "dictionary") == 0)            dictionary_ = attr->Value();          else if (std::strcmp(name, "id") == 0)            id_ = attr->Value();          else if (std::strcmp(name, "presence") == 0)            presence_ = attr->Value();          else if (std::strcmp(name, "charset") == 0)            charset_ = attr->Value();          else if (std::strcmp(name, "mfast:tag") == 0)            tag_ = attr->Value();          else if (std::strcmp(name, "decimalPlaces") == 0)            decimal_place_ = attr->Value();          attr = attr->Next();        }      }

下一步调用build过程,代码如下。首先获取节点名称template,然后从本类型或事先注册的map里面检索对应名称的instruction,这一步原理还不清楚。然后调用instruction的accept过程,实质是调用field_builder的visit函数,visit再调用相应类型的built函数,或者直接调用parent_->add_instruction过程,讲此过程注册进templates_builder,即注册进dynamic_templates_description。至此,完成一个template的解析。

  void field_builder::build()    {      const field_instruction* prototype =        find_prototype(resolve_field_type(element_));      if (prototype) {        prototype->accept(*this, 0);      }    }    const char* field_builder::resolve_field_type(const XMLElement& element)    {      field_type_name_ = element.Name();      content_element_ = &element;      if (std::strcmp(field_type_name_, "field") == 0 ) {        content_element_ = element.FirstChildElement();        if (content_element_) {          field_type_name_ = content_element_->Name();          if (strcmp(field_type_name_, "type")==0) {            field_type_name_ = name_;            name_ = 0;            fast_xml_attributes::set(content_element_->FirstAttribute());            if (name_ == 0)              throw std::runtime_error("type element does not have a name");            std::swap(field_type_name_, name_);          }          else {            fast_xml_attributes::set(content_element_->FirstAttribute());          }        }        else {          throw std::runtime_error("field element must have a  child element");        }      }      resolved_ns_ = ns_;   //ns_继承自fast_xml_attributes,resolved_ns_继承自field_builder_base      if (resolved_ns_ == 0 && parent_) {        resolved_ns_ = parent_->resolved_ns();      }      return field_type_name_;    }const field_instruction* field_builder::find_prototype(const char* type_name)    {      if (type_name == 0)      {        BOOST_THROW_EXCEPTION(fast_static_error("S1") << reason_info("no field type specified"));      }      const field_instruction* instruction = 0;      if (std::strcmp(type_name, "string") == 0) {        if (this->charset_ == 0)          this->charset_ = get_optional_attr(element_, "charset", "ascii");        if (std::strcmp(this->charset_, "unicode") == 0 )        {          static unicode_field_instruction prototype (operator_none,presence_mandatory,0,0,"",0, string_value_storage(), 0, "", "");          instruction = &prototype;        }      }      else if (std::strcmp(type_name, "templateRef") == 0)      {        return templateref_instruction::default_instruction()[0];      }      else if (std::strcmp(type_name, "typeRef") == 0 || std::strcmp(type_name, "length") == 0)      {        return 0;      }      if (instruction == 0) {        instruction = this->find_type(ns_, type_name);      }      if ( instruction == 0 )      {        BOOST_THROW_EXCEPTION(fast_static_error("S1") << reason_info((std::string("Invalid field type specified : ") + type_name)));      }      return instruction;    }
原创粉丝点击