1 // $Id: xml.cpp,v 1.124 2010/09/27 03:19:46 bobgian Exp $
2
3 /*
4 Copyright 2002 Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein
5
6 This software is distributed free of charge for non-commercial use
7 and is copyrighted. Of course, we do not guarantee that the software
8 works, and are not responsible for any damage you may cause or have.
9 */
10
11 #include <cassert>
12
13 #include "errhandling.h"
14 #include "front_end_warnings.h"
15 #include "stringx.h"
16 #include "tinyxml.h"
17 #include "xml.h"
18 #include "xml_strings.h"
19
20 using std::string;
21
22 //------------------------------------------------------------------------------------
23
XmlErrorSupport(string fileName)24 XmlErrorSupport::XmlErrorSupport(string fileName)
25 :
26 m_fileName(fileName),
27 m_errorMessage("")
28 {
29 }
30
~XmlErrorSupport()31 XmlErrorSupport::~XmlErrorSupport()
32 {
33 }
34
35 string
GetFileName()36 XmlErrorSupport::GetFileName()
37 {
38 return m_fileName;
39 }
40
41 void
ThrowDataError(const string & reason)42 XmlErrorSupport::ThrowDataError(const string& reason)
43 {
44 m_errorMessage.append(xmlstr::XML_ERR_DATA_ERR_0 + reason);
45 incorrect_data e(m_errorMessage);
46 throw e;
47 }
48
49 void
ThrowDataError(const string & reason,long lineno)50 XmlErrorSupport::ThrowDataError(const string& reason, long lineno)
51 {
52 m_errorMessage.append( xmlstr::XML_ERR_DATA_ERR_0
53 + xmlstr::XML_ERR_DATA_ERR_1
54 + m_fileName
55 + xmlstr::XML_ERR_DATA_ERR_2
56 + ToString(lineno)
57 + xmlstr::XML_ERR_DATA_ERR_3
58 + reason);
59 incorrect_data e(m_errorMessage);
60 throw e;
61 }
62
63 void
ThrowFileError(const string & reason)64 XmlErrorSupport::ThrowFileError(const string& reason)
65 {
66 m_errorMessage.append(xmlstr::XML_ERR_FILE_ERR + reason);
67 file_error e(m_errorMessage);
68 throw e;
69 }
70
71 void
ThrowXMLError(const string & reason)72 XmlErrorSupport::ThrowXMLError(const string& reason)
73 {
74 m_errorMessage.append(xmlstr::XML_ERR_0 + reason);
75 incorrect_xml e(m_errorMessage);
76 throw e;
77 }
78
79 void
ThrowXMLError(const string & reason,long lineno)80 XmlErrorSupport::ThrowXMLError(const string& reason, long lineno)
81 {
82 m_errorMessage.append(xmlstr::XML_ERR_0
83 + xmlstr::XML_ERR_1
84 + m_fileName
85 + xmlstr::XML_ERR_2
86 + ToString(lineno)
87 + xmlstr::XML_ERR_3
88 + reason);
89 incorrect_xml e(m_errorMessage);
90 throw e;
91 }
92
93 void
ThrowInternalXMLError(const string & reason)94 XmlErrorSupport::ThrowInternalXMLError(const string& reason)
95 {
96 m_errorMessage.append(xmlstr::XML_ERR_INTERNAL + reason);
97 incorrect_xml e(m_errorMessage);
98 throw e;
99 }
100
101 //------------------------------------------------------------------------------------
102
XmlParser(ParseTreeSchema & schema,FrontEndWarnings & warnings)103 XmlParser::XmlParser(ParseTreeSchema & schema, FrontEndWarnings & warnings)
104 :
105 XmlErrorSupport(defaults::datafilename),
106 m_schema(schema),
107 m_frontEndWarnings(warnings)
108 {
109 }
110
~XmlParser()111 XmlParser::~XmlParser()
112 {
113 }
114
115 void
ParseFileData(string fileName)116 XmlParser::ParseFileData(string fileName)
117 {
118 m_fileName = fileName;
119 m_document.LoadFile(GetFileName());
120 if(m_document.Error())
121 {
122 throw tixml_error(m_document.ErrorDesc()); // EWFIX -- row ??
123 }
124 else
125 // XML parser is happy, but now we need to make
126 // sure that we've got data
127 {
128 TiXmlElement * root = GetRootElement();
129 if(root == NULL)
130 {
131 string msg = GetFileName() + ":"
132 + xmlstr::XML_ERR_NO_XML_DATA;
133 throw tixml_error(msg);
134 }
135 }
136
137 checkSchema();
138 }
139
140 TiXmlElement *
GetRootElement()141 XmlParser::GetRootElement()
142 {
143 return m_document.RootElement();
144 }
145
146 void
checkSchema()147 XmlParser::checkSchema()
148 {
149 TiXmlElement * rootElement = GetRootElement();
150 TiXmlNode * extraNode = rootElement->NextSibling();
151 while(extraNode != NULL)
152 {
153 if(extraNode->Type() != TiXmlNode::TINYXML_COMMENT)
154 {
155 ThrowXMLError( xmlstr::XML_ERR_EXTRA_TAG_TOP_0
156 + extraNode->Value()
157 + xmlstr::XML_ERR_EXTRA_TAG_TOP_1,
158 extraNode->Row());
159 }
160 extraNode = extraNode->NextSibling();
161 }
162 checkSchema(rootElement);
163 }
164
165 void
checkAttrPresent(TiXmlElement * elem,string attrName)166 XmlParser::checkAttrPresent(TiXmlElement * elem, string attrName)
167 {
168 const string * attrValue = elem->Attribute(attrName);
169 if(!attrValue)
170 {
171 ThrowXMLError( xmlstr::XML_ERR_ATTR_MISSING_0
172 +attrName
173 +xmlstr::XML_ERR_ATTR_MISSING_1
174 +elem->Value()
175 +xmlstr::XML_ERR_ATTR_MISSING_2,
176 elem->Row());
177
178 }
179 }
180
181 void
checkElemPresent(TiXmlElement * elem,string elemName)182 XmlParser::checkElemPresent(TiXmlElement * elem, string elemName)
183 {
184 TiXmlNode * firstChild = elem->IterateChildren(elemName,NULL);
185 if(firstChild == NULL)
186 {
187 ThrowXMLError( xmlstr::XML_ERR_ELEM_MISSING_0
188 +elemName
189 +xmlstr::XML_ERR_ELEM_MISSING_1
190 +elem->Value()
191 +xmlstr::XML_ERR_ELEM_MISSING_2,
192 elem->Row());
193 }
194 }
195
196 void
checkAttrAllowed(TiXmlElement * parent,string attrName)197 XmlParser::checkAttrAllowed(TiXmlElement * parent, string attrName)
198 {
199 if(!m_schema.AllowsAttribute(string(parent->Value()),attrName,parent->Row()))
200 {
201 ThrowXMLError(xmlstr::XML_ERR_UNEXPECTED_ATTR_0
202 + attrName
203 + xmlstr::XML_ERR_UNEXPECTED_ATTR_1
204 + parent->Value()
205 + xmlstr::XML_ERR_UNEXPECTED_ATTR_2,
206 parent->Row());
207 }
208 }
209
210 void
checkElemCount(TiXmlElement * parent,string childName)211 XmlParser::checkElemCount(TiXmlElement * parent, string childName)
212 {
213 TiXmlNode * child = parent->IterateChildren(childName,NULL);
214 assert(child != NULL); // because we found it as child of parent
215
216 if(!m_schema.AllowsElement(string(parent->Value()),childName,child->Row()))
217 {
218 ThrowXMLError(xmlstr::XML_ERR_UNEXPECTED_TAG_0
219 + childName
220 + xmlstr::XML_ERR_UNEXPECTED_TAG_1
221 + parent->Value()
222 + xmlstr::XML_ERR_UNEXPECTED_TAG_2,
223 child->Row());
224 }
225
226 // now check if there is more than one
227 child = parent->IterateChildren(childName,child);
228 if(child != NULL)
229 {
230 if(!m_schema.AllowsAdditionalElements(string(parent->Value()),childName,child->Row()))
231 {
232 ThrowXMLError(xmlstr::XML_ERR_EXTRA_TAG_0
233 + childName
234 + xmlstr::XML_ERR_EXTRA_TAG_1
235 + parent->Value()
236 + xmlstr::XML_ERR_EXTRA_TAG_2,
237 child->Row());
238 }
239 }
240 }
241
242 void
checkSchema(TiXmlElement * parentElem)243 XmlParser::checkSchema(TiXmlElement * parentElem)
244 {
245
246 string parentString(parentElem->Value());
247
248 // check all required attributes are present
249 std::set<string> attrs = m_schema.RequiredAttributes(parentString,parentElem->Row());
250 for(std::set<string>::const_iterator i= attrs.begin(); i != attrs.end(); i++)
251 {
252 checkAttrPresent(parentElem,*i);
253 }
254
255 // check all required elements are present
256 std::set<string> elems = m_schema.RequiredElements(parentString,parentElem->Row());
257 for(std::set<string>::const_iterator i= elems.begin(); i != elems.end(); i++)
258 {
259 checkElemPresent(parentElem,*i);
260 }
261
262 // check all attributes present are allowed
263 for(TiXmlAttribute * attr = parentElem->FirstAttribute(); attr != NULL; attr = attr->Next())
264 {
265 string attrName(attr->Name());
266 checkAttrAllowed(parentElem,attrName);
267 }
268
269 // check all elements present are allowed and in right number
270 TiXmlNode * child = NULL;
271 while ((child = parentElem->IterateChildren(child)))
272 {
273 if(child->Type() == TiXmlNode::TINYXML_ELEMENT)
274 {
275 TiXmlElement * newElem = child->ToElement();
276 string childString(newElem->Value());
277 if(m_schema.DeprecatedElement(parentString,childString,newElem->Row()))
278 {
279 m_frontEndWarnings.AddWarning(xmlstr::XML_WARN_DEPRECATED_TAG_0
280 + childString
281 + xmlstr::XML_WARN_DEPRECATED_TAG_1
282 + parentString
283 + xmlstr::XML_WARN_DEPRECATED_TAG_2
284 + ToString(newElem->Row()));
285 }
286 else
287 {
288 checkElemCount(parentElem,string(childString));
289 checkSchema(newElem); // recursive check
290 }
291 }
292 }
293 }
294
295 //____________________________________________________________________________________
296