mFAST fast_type_gen流程详解

先打开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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值