Line data Source code
1 : #include "expatmodelparser.hh"
2 : #include "tree/tree_util.hh"
3 : #include <string>
4 :
5 :
6 :
7 0 : IOError::IOError(std::string message) throw() : std::runtime_error(message) { }
8 :
9 0 : ExpatError::ExpatError(XML_Error error_code) throw() : std::runtime_error(""), error_code(error_code) { }
10 0 : const char* ExpatError::what() const throw()
11 : {
12 0 : return XML_ErrorString(error_code);
13 : }
14 :
15 52 : ExpatModelParser::ExpatModelParser(ModelHandlerPtr h) : handler(h)
16 : {
17 52 : parser = XML_ParserCreate(NULL);
18 52 : XML_SetUserData(parser, this);
19 :
20 52 : XML_SetStartElementHandler(parser, ExpatModelParser::on_start_element);
21 52 : XML_SetEndElementHandler(parser, ExpatModelParser::on_end_element);
22 52 : XML_SetCharacterDataHandler(parser, ExpatModelParser::on_characters);
23 52 : }
24 :
25 104 : ExpatModelParser::~ExpatModelParser()
26 : {
27 52 : XML_ParserFree(parser);
28 52 : }
29 :
30 52 : void ExpatModelParser::parse_file(const std::string& filename)
31 : {
32 104 : std::ifstream ifs(filename.c_str());
33 52 : if (ifs.fail()) {
34 0 : throw IOError("Cannot open the file");
35 : }
36 52 : parse_stream(ifs);
37 52 : }
38 :
39 226 : void ExpatModelParser::parse_stream(std::istream& in)
40 : {
41 : XML_Status status;
42 400 : while(in.good())
43 : {
44 174 : char* buffer = (char*) XML_GetBuffer(parser, BUFFER_SIZE);
45 174 : in.read(buffer, BUFFER_SIZE);
46 174 : status = XML_ParseBuffer(parser, in.gcount(), in.eof());
47 :
48 174 : if (status == XML_STATUS_ERROR)
49 : {
50 0 : XML_Error error_code = XML_GetErrorCode(parser);
51 0 : throw ExpatError(error_code);
52 : }
53 : }
54 52 : }
55 :
56 27309 : void ExpatModelParser::on_start_element(void *userData, const XML_Char *cname, const XML_Char **catts)
57 : {
58 27309 : ExpatModelParser* self = (ExpatModelParser*) userData;
59 :
60 : // Convert c variables to c++ objects
61 54618 : XmlString name = cname;
62 27309 : size_t pos = name.find_last_of(":");
63 27309 : if (pos != std::string::npos)
64 0 : name = name.substr(pos+1, name.size());
65 54618 : std::map<XmlString, XmlString> atts;
66 66327 : for(int i = 0; catts[i] != NULL; i +=2)
67 : {
68 78036 : XmlString attr_name = catts[i];
69 78036 : XmlString attr_value = catts[i + 1];
70 39018 : atts[attr_name] = attr_value;
71 : }
72 :
73 27309 : if (name == "model") { // <model>
74 52 : self->handler->on_read_model(atts["formalismUrl"]);
75 52 : self->state.push(MODEL);
76 :
77 27257 : } else if (name == "node") { // <node id= type= >
78 1362 : self->id = atts["id"];
79 1362 : self->type = atts["nodeType"];
80 1362 : self->attributes.clear();
81 1362 : self->references.clear();
82 1362 : self->state.push(NODE);
83 :
84 25895 : } else if (name == "arc") { // <arc id= type= source= target= >
85 2669 : self->id = atts["id"];
86 2669 : self->type = atts["arcType"];
87 2669 : self->source = atts["source"];
88 2669 : self->target = atts["target"];
89 2669 : self->attributes.clear();
90 2669 : self->references.clear();
91 2669 : self->state.push(ARC);
92 :
93 23226 : } else if (name == "attribute") { // <attribute name= >
94 46452 : std::string attributeName = atts["name"];
95 :
96 : // root GrML attribute
97 23226 : if (self->state.top() != ATTRIBUTE) {
98 6511 : self->attribute.clear();
99 6511 : self->attributeIterator = self->attribute.insert(self->attribute.begin(), attributeName);
100 : }
101 :
102 : // child GrML attribute
103 : else {
104 16715 : self->attributeIterator = self->attribute.append_child(self->attributeIterator, attributeName);
105 : }
106 :
107 23226 : self->xmlData.clear();
108 23226 : self->state.push(ATTRIBUTE);
109 0 : } else if (name == "ref") {
110 0 : self->references.push_back(atts["href"]);
111 : }
112 27309 : }
113 :
114 27309 : void ExpatModelParser::on_end_element(void *userData, const XML_Char *cname)
115 : {
116 27309 : ExpatModelParser* self = (ExpatModelParser*) userData;
117 54618 : XmlString name = cname;
118 : try{
119 27309 : size_t pos = name.find_last_of(":");
120 27309 : if (pos != std::string::npos)
121 0 : name = name.substr(pos+1, name.size());
122 27309 : if (name == "model") { // </model>
123 52 : self->state.pop();
124 :
125 27257 : } else if (name == "node") { // </node>
126 1362 : self->state.pop();
127 1362 : self->handler->on_read_node(self->id, self->type, self->attributes, self->references);
128 :
129 25895 : } else if (name == "arc") { // </arc>
130 2669 : self->state.pop();
131 2669 : self->handler->on_read_arc(self->id, self->type, self->source, self->target, self->attributes, self->references);
132 :
133 23226 : } else if (name == "attribute") { // </attribute>
134 23226 : self->state.pop();
135 :
136 : // leaf node with data
137 23226 : if (!self->xmlData.empty() && self->attribute.number_of_children(self->attributeIterator) == 0) {
138 9886 : self->trim(self->xmlData);
139 9886 : self->attribute.append_child(self->attributeIterator, self->xmlData);
140 9886 : self->xmlData.clear();
141 : }
142 :
143 : // root GrML attribute
144 23226 : if (self->state.top() == MODEL) {
145 106 : self->handler->on_read_model_attribute(self->attribute);
146 23120 : } else if (self->state.top() == NODE || self->state.top() == ARC) {
147 6405 : self->attributes[*self->attribute.begin()] = self->attribute;
148 : }
149 :
150 : // child GrML attribute
151 : else {
152 16715 : self->attributeIterator = self->attribute.parent(self->attributeIterator);
153 : }
154 : }
155 0 : } catch (std::exception &e){
156 0 : std::cerr << "fail to parse '"+name+"' :"+e.what() << std::endl;
157 0 : exit(EXIT_FAILURE);
158 : }
159 27309 : }
160 :
161 102387 : void ExpatModelParser::on_characters(void *userData, const XML_Char *s, int len)
162 : {
163 102387 : ExpatModelParser* self = (ExpatModelParser*) userData;
164 102387 : self->xmlData += std::string(s, len);
165 102387 : }
166 :
167 9886 : void ExpatModelParser::trim(std::string& s) {
168 95640 : s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c){return !std::isspace(c);}));
169 79279 : s.erase(std::find_if(s.rbegin(), s.rend(), [](int c){return !std::isspace(c);}).base(), s.end());
170 9991 : }
|