XSDSchemaParser.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2017 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include <exception>
  14. #include "XSDSchemaParser.hpp"
  15. #include "Exceptions.hpp"
  16. #include "SchemaValue.hpp"
  17. #include "XSDComponentParser.hpp"
  18. #include "XSDValueSetParser.hpp"
  19. #include "SchemaTypeStringLimits.hpp"
  20. #include "SchemaTypeIntegerLimits.hpp"
  21. #include "EnvironmentEventHandlers.hpp"
  22. #include "Utils.hpp"
  23. namespace pt = boost::property_tree;
  24. bool XSDSchemaParser::doParse(const std::string &configPath, const std::string &masterConfigFile, const std::vector<std::string> &cfgParms)
  25. {
  26. bool rc = true;
  27. //
  28. // Add some default types to the config. Note changing values for limits
  29. std::shared_ptr<SchemaTypeStringLimits> pStringLimits;
  30. std::shared_ptr<SchemaTypeIntegerLimits> pIntLimits;
  31. std::shared_ptr<SchemaType> pType = std::make_shared<SchemaType>("xs:string");
  32. pType->setBaseType("string");
  33. pStringLimits = std::make_shared<SchemaTypeStringLimits>();
  34. pType->setLimits(pStringLimits);
  35. m_pSchemaItem->addSchemaValueType(pType);
  36. pType = std::make_shared<SchemaType>("xs:token");
  37. pType->setBaseType("string");
  38. pStringLimits = std::make_shared<SchemaTypeStringLimits>();
  39. pType->setLimits(pStringLimits);
  40. m_pSchemaItem->addSchemaValueType(pType);
  41. pType = std::make_shared<SchemaType>("xs:boolean");
  42. pType->setBaseType("boolean");
  43. std::shared_ptr<SchemaTypeLimits> pBoolLimits = std::make_shared<SchemaTypeStringLimits>();
  44. pBoolLimits->addAllowedValue("true");
  45. pBoolLimits->addAllowedValue("false");
  46. pType->setLimits(pBoolLimits);
  47. m_pSchemaItem->addSchemaValueType(pType);
  48. pType = std::make_shared<SchemaType>("xs:integer");
  49. pType->setBaseType("integer");
  50. pIntLimits = std::make_shared<SchemaTypeIntegerLimits>();
  51. pType->setLimits(pIntLimits);
  52. m_pSchemaItem->addSchemaValueType(pType);
  53. pType = std::make_shared<SchemaType>("xs:nonNegativeInteger");
  54. pType->setBaseType("integer");
  55. pIntLimits = std::make_shared<SchemaTypeIntegerLimits>();
  56. pIntLimits->setMinInclusive(0);
  57. pType->setLimits(pIntLimits);
  58. m_pSchemaItem->addSchemaValueType(pType);
  59. pType = std::make_shared<SchemaType>("xs:positiveInteger");
  60. pType->setBaseType("integer");
  61. pIntLimits = std::make_shared<SchemaTypeIntegerLimits>();
  62. pIntLimits->setMinInclusive(1);
  63. pType->setLimits(pIntLimits);
  64. m_pSchemaItem->addSchemaValueType(pType);
  65. pType = std::make_shared<SchemaType>("xs:unsignedInt");
  66. pType->setBaseType("integer");
  67. pIntLimits = std::make_shared<SchemaTypeIntegerLimits>();
  68. pIntLimits->setMinInclusive(0);
  69. pType->setLimits(pIntLimits);
  70. m_pSchemaItem->addSchemaValueType(pType);
  71. //
  72. // Get our specific XSD parameters from the input
  73. m_basePath = configPath;
  74. m_masterXSDFilename = masterConfigFile;
  75. //m_buildsetFilename = cfgParms[2];
  76. parseXSD(m_masterXSDFilename);
  77. return rc;
  78. }
  79. void XSDSchemaParser::parseXSD(const std::string &filename)
  80. {
  81. pt::ptree xsdTree;
  82. std::string fpath = m_basePath + filename;
  83. try
  84. {
  85. pt::read_xml(fpath, xsdTree, pt::xml_parser::trim_whitespace | pt::xml_parser::no_comments);
  86. }
  87. catch (const std::exception &e)
  88. {
  89. std::string xmlError = e.what();
  90. ParseException pe("Unable to read/parse file. Check that file is formatted correctly. Error = " + xmlError);
  91. pe.addFilename(filename);
  92. throw(pe);
  93. }
  94. try
  95. {
  96. auto schemaIt = xsdTree.find("xs:schema");
  97. pt::ptree emptyTree;
  98. const pt::ptree &keys = schemaIt->second.get_child("", emptyTree);
  99. parseXSD(keys);
  100. }
  101. catch (ParseException &pe)
  102. {
  103. pe.addFilename(filename);
  104. throw(pe);
  105. }
  106. }
  107. void XSDSchemaParser::parseXSD(const pt::ptree &keys)
  108. {
  109. for (auto it = keys.begin(); it != keys.end(); ++it)
  110. {
  111. //
  112. // Element parent (a type in realilty) and the element name help figure out how to process the XSD schema element
  113. std::string elemType = it->first;
  114. if (elemType == "xs:include")
  115. {
  116. std::string schemaFile = getXSDAttributeValue(it->second, "<xmlattr>.schemaLocation");
  117. if (m_pSchemaItem->addUniqueName(schemaFile))
  118. {
  119. parseXSD(schemaFile);
  120. }
  121. }
  122. else if (elemType == "xs:simpleType")
  123. {
  124. parseSimpleType(it->second);
  125. }
  126. else if (elemType == "xs:complexType")
  127. {
  128. parseComplexType(it->second);
  129. }
  130. else if (elemType == "xs:attributeGroup")
  131. {
  132. parseAttributeGroup(it->second);
  133. }
  134. else if (elemType == "xs:attribute")
  135. {
  136. parseAttribute(it->second);
  137. }
  138. else if (elemType == "xs:sequence")
  139. {
  140. parseXSD(it->second.get_child("", pt::ptree()));
  141. }
  142. else if (elemType == "xs:element")
  143. {
  144. parseElement(it->second);
  145. }
  146. else if (elemType == "xs:annotation")
  147. {
  148. parseAnnotation(it->second);
  149. }
  150. }
  151. }
  152. std::string XSDSchemaParser::getXSDAttributeValue(const pt::ptree &tree, const std::string &attrName, bool throwIfNotPresent, const std::string &defaultVal) const
  153. {
  154. std::string value = defaultVal;
  155. try
  156. {
  157. value = tree.get<std::string>(attrName);
  158. }
  159. catch (std::exception &e)
  160. {
  161. if (throwIfNotPresent)
  162. throw(ParseException("Missing attribute " + attrName + "."));
  163. }
  164. return value;
  165. }
  166. void XSDSchemaParser::parseSimpleType(const pt::ptree &typeTree)
  167. {
  168. std::shared_ptr<SchemaType> pCfgType = getType(typeTree, true);
  169. m_pSchemaItem->addSchemaValueType(pCfgType);
  170. }
  171. std::shared_ptr<SchemaValue> XSDSchemaParser::parseAttribute(const pt::ptree &attr)
  172. {
  173. std::shared_ptr<SchemaValue> pCfgValue = getSchemaValue(attr);
  174. m_pSchemaItem->addAttribute(pCfgValue);
  175. return pCfgValue;
  176. }
  177. void XSDSchemaParser::parseAttributeGroup(const pt::ptree &attributeTree)
  178. {
  179. std::string groupName = getXSDAttributeValue(attributeTree, "<xmlattr>.name", false, ""); // only a named attributeGroup is supported
  180. //
  181. // If there is a name (for the attribute group) then a group of attributes is being defined. Create the group, parese it, and add it as a
  182. // schema type that can be reused (usually with a ref= reference in another attribute group schema item)
  183. if (!groupName.empty())
  184. {
  185. std::shared_ptr<SchemaItem> pValueSet = std::make_shared<SchemaItem>(groupName, "valueset", m_pSchemaItem);
  186. std::shared_ptr<XSDValueSetParser> pXSDValueSetParaser = std::make_shared<XSDValueSetParser>(pValueSet);
  187. std::string groupByName = getXSDAttributeValue(attributeTree, "<xmlattr>.groupByName", false, "");
  188. pXSDValueSetParaser->setGroupByName(groupByName);
  189. pXSDValueSetParaser->parseXSD(attributeTree.get_child("", pt::ptree()));
  190. m_pSchemaItem->addSchemaType(pValueSet, groupName);
  191. }
  192. //
  193. // Is it a reference to a named attribute group previously saved? If so, grab the defined attributes and add them.
  194. else
  195. {
  196. std::string refName = getXSDAttributeValue(attributeTree, "<xmlattr>.ref", false, ""); // only a named attributeGroup is supported
  197. if (!refName.empty())
  198. {
  199. std::shared_ptr<SchemaItem> pValueSet = m_pSchemaItem->getSchemaType(refName, true);
  200. if (pValueSet)
  201. {
  202. std::vector<std::shared_ptr<SchemaValue>> attributes;
  203. pValueSet->getAttributes(attributes);
  204. std::string groupByName = getXSDAttributeValue(attributeTree, "<xmlattr>.groupByName", false, "");
  205. if (!groupByName.empty())
  206. {
  207. for (auto &attr: attributes)
  208. {
  209. attr->setGroupByName(groupByName);
  210. }
  211. }
  212. m_pSchemaItem->addAttribute(attributes);
  213. //
  214. // Add any unique valueset references
  215. m_pSchemaItem->addReferenceToUniqueAttributeValueSet(pValueSet);
  216. }
  217. }
  218. }
  219. }
  220. void XSDSchemaParser::parseComplexType(const pt::ptree &typeTree)
  221. {
  222. std::string complexTypeName = getXSDAttributeValue(typeTree, "<xmlattr>.name", false, "");
  223. if (!complexTypeName.empty())
  224. {
  225. std::shared_ptr<SchemaItem> pComplexType = std::make_shared<SchemaItem>(complexTypeName, "component", m_pSchemaItem);
  226. pComplexType->setProperty("itemType", complexTypeName);
  227. pt::ptree childTree = typeTree.get_child("", pt::ptree());
  228. if (!childTree.empty())
  229. {
  230. std::shared_ptr<XSDSchemaParser> pXSDParaser = std::make_shared<XSDSchemaParser>(pComplexType);
  231. pXSDParaser->parseXSD(childTree);
  232. m_pSchemaItem->addSchemaType(pComplexType, complexTypeName);
  233. }
  234. else
  235. {
  236. throw(ParseException("Complex type definition empty: " + complexTypeName));
  237. }
  238. }
  239. //
  240. // Just a complexType delimiter, ignore and parse the children
  241. else
  242. {
  243. parseXSD(typeTree.get_child("", pt::ptree()));
  244. }
  245. }
  246. void XSDSchemaParser::parseElement(const pt::ptree &elemTree)
  247. {
  248. //
  249. // Get a couple attributes to help figure out how to handle the element
  250. std::string elementName = elemTree.get("<xmlattr>.name", "");
  251. std::string category = elemTree.get("<xmlattr>.hpcc:category", "");
  252. pt::ptree emptyTree;
  253. pt::ptree childTree = elemTree.get_child("", emptyTree);
  254. if (category == "root")
  255. {
  256. m_pSchemaItem->setProperty("name", elementName);
  257. parseXSD(childTree);
  258. }
  259. else
  260. {
  261. std::string className = elemTree.get("<xmlattr>.hpcc:class", "");
  262. std::string displayName = elemTree.get("<xmlattr>.hpcc:displayName", elementName);
  263. std::string tooltip = elemTree.get("<xmlattr>.hpcc:tooltip", "");
  264. std::string typeName = elemTree.get("<xmlattr>.type", "");
  265. std::string itemType = elemTree.get("<xmlattr>.hpcc:itemType", "");
  266. std::string insertLimitType = elemTree.get("<xmlattr>.hpcc:insertLimitType", "");
  267. std::string insertLimitData = elemTree.get("<xmlattr>.hpcc:insertLimitData", "");
  268. unsigned minOccurs = elemTree.get("<xmlattr>.minOccurs", 1);
  269. std::string maxOccursStr = elemTree.get("<xmlattr>.maxOccurs", "1");
  270. unsigned maxOccurs = (maxOccursStr != "unbounded") ? stoi(maxOccursStr) : UINT_MAX;
  271. std::shared_ptr<SchemaItem> pNewSchemaItem = std::make_shared<SchemaItem>(elementName, className, m_pSchemaItem);
  272. if (!className.empty()) pNewSchemaItem->setProperty("className", className);
  273. if (!displayName.empty()) pNewSchemaItem->setProperty("displayName", displayName);
  274. if (!tooltip.empty()) pNewSchemaItem->setProperty("tooltip", tooltip);
  275. if (!insertLimitType.empty()) pNewSchemaItem->setProperty("insertLimitType", insertLimitType);
  276. if (!insertLimitData.empty()) pNewSchemaItem->setProperty("insertLimitData", insertLimitData);
  277. pNewSchemaItem->setProperty("itemType", itemType);
  278. pNewSchemaItem->setProperty("category", category.empty() ? displayName : category );
  279. pNewSchemaItem->setMinInstances(minOccurs);
  280. pNewSchemaItem->setMaxInstances(maxOccurs);
  281. pNewSchemaItem->setHidden(elemTree.get("<xmlattr>.hpcc:hidden", "false") == "true");
  282. //
  283. // Type specified?
  284. if (!typeName.empty())
  285. {
  286. //
  287. // If a simple type, then it represents the element value type, so allocate a value object, set its type and add
  288. // it to the item.
  289. const std::shared_ptr<SchemaType> pSimpleType = m_pSchemaItem->getSchemaValueType(typeName, false);
  290. if (pSimpleType != nullptr)
  291. {
  292. std::shared_ptr<SchemaValue> pCfgValue = std::make_shared<SchemaValue>(""); // no name value since it's the element's value
  293. pCfgValue->setType(pSimpleType); // will throw if type is not defined
  294. pNewSchemaItem->setItemSchemaValue(pCfgValue);
  295. std::shared_ptr<XSDSchemaParser> pXSDParaser = std::make_shared<XSDSchemaParser>(pNewSchemaItem);
  296. pXSDParaser->parseXSD(childTree);
  297. m_pSchemaItem->addChild(pNewSchemaItem);
  298. }
  299. else
  300. {
  301. //
  302. // Wasn't a simple type, complex?
  303. std::shared_ptr<SchemaItem> pConfigType = m_pSchemaItem->getSchemaType(typeName, false);
  304. if (pConfigType != nullptr)
  305. {
  306. //
  307. // A complex type was found. Insert it
  308. std::vector<std::shared_ptr<SchemaItem>> typeChildren;
  309. pConfigType->getChildren(typeChildren);
  310. for (auto childIt = typeChildren.begin(); childIt != typeChildren.end(); ++childIt)
  311. {
  312. std::shared_ptr<SchemaItem> pNewItem = std::make_shared<SchemaItem>(*(*childIt));
  313. pNewItem->setParent(m_pSchemaItem);
  314. m_pSchemaItem->addChild(pNewItem);
  315. }
  316. }
  317. else
  318. {
  319. std::string msg = "Unable to find type " + typeName + " when parsing element " + elementName;
  320. throw(ParseException(msg));
  321. }
  322. }
  323. }
  324. else
  325. {
  326. //
  327. // No type, just continue parsing a new element
  328. //pNewSchemaItem = std::make_shared<SchemaItem>(elementName, className, m_pSchemaItem);
  329. std::shared_ptr<XSDSchemaParser> pXSDParaser = std::make_shared<XSDSchemaParser>(pNewSchemaItem);
  330. pXSDParaser->parseXSD(childTree);
  331. m_pSchemaItem->addChild(pNewSchemaItem);
  332. }
  333. }
  334. }
  335. void XSDSchemaParser::parseAnnotation(const pt::ptree &elemTree)
  336. {
  337. pt::ptree emptyTree;
  338. const pt::ptree &keys = elemTree.get_child("", emptyTree);
  339. //
  340. // Parse app info sections
  341. for (auto it = keys.begin(); it != keys.end(); ++it)
  342. {
  343. if (it->first == "xs:appinfo")
  344. {
  345. parseAppInfo(it->second);
  346. }
  347. }
  348. }
  349. void XSDSchemaParser::parseAppInfo(const pt::ptree &elemTree)
  350. {
  351. std::string appInfoType = elemTree.get("<xmlattr>.hpcc:infoType", "");
  352. pt::ptree emptyTree, childTree;
  353. //
  354. // Process the app info based on its type
  355. if (appInfoType == "event")
  356. {
  357. childTree = elemTree.get_child("", emptyTree);
  358. std::string eventType = getXSDAttributeValue(childTree, "eventType");
  359. //
  360. // Fir a create event type, get the eventAction attrbute to decide what to do
  361. if (eventType == "create")
  362. {
  363. std::string eventAction = getXSDAttributeValue(childTree, "eventAction");
  364. //
  365. // addAttributeDependencies is used to set dependent values for an attribute based on the value of another attribute.
  366. if (eventAction == "addAttributeDependencies")
  367. {
  368. std::shared_ptr<AttributeDependencyCreateEventHandler> pDep = std::make_shared<AttributeDependencyCreateEventHandler>();
  369. pt::ptree dataTree = childTree.get_child("eventData", emptyTree);
  370. for (auto it = dataTree.begin(); it != dataTree.end(); ++it)
  371. {
  372. if (it->first == "itemType")
  373. {
  374. pDep->setItemType(it->second.data());
  375. }
  376. else if (it->first == "attribute")
  377. {
  378. std::string attrName = getXSDAttributeValue(it->second, "<xmlattr>.attributeName");
  379. std::string attrVal = getXSDAttributeValue(it->second, "<xmlattr>.attributeValue");
  380. std::string depAttr = getXSDAttributeValue(it->second, "<xmlattr>.dependentAttribute");
  381. std::string depVal = getXSDAttributeValue(it->second, "<xmlattr>.dependentValue");
  382. pDep->addDependency(attrName, attrVal, depAttr, depVal);
  383. }
  384. else if (it->first == "match")
  385. {
  386. std::string attrName = it->second.get("eventNodeAttribute", "").data();
  387. pDep->setEventNodeAttributeName(attrName);
  388. std::string matchAttrName = it->second.get("targetAttribute", "");
  389. if (!matchAttrName.empty())
  390. {
  391. pDep->setTargetAttributeName(matchAttrName);
  392. }
  393. std::string path = it->second.get("targetPath", "");
  394. pDep->setTargetPath(path);
  395. }
  396. }
  397. m_pSchemaItem->addEventHandler(pDep);
  398. }
  399. //
  400. // Insert XML is ued to insert XML ino the environment based on what's in the eventData section
  401. else if (eventAction == "insertXML")
  402. {
  403. std::shared_ptr<InsertEnvironmentDataCreateEventHandler> pInsert = std::make_shared<InsertEnvironmentDataCreateEventHandler>();
  404. pt::ptree dataTree = childTree.get_child("eventData", emptyTree);
  405. for (auto it = dataTree.begin(); it != dataTree.end(); ++it)
  406. {
  407. //
  408. // itemTye is the type of the item that was created for which the create event shall be sent.
  409. if (it->first == "itemType")
  410. {
  411. pInsert->setItemType(it->second.data());
  412. }
  413. //
  414. // The match section is optional. It is used to further qualify the conditions when XML is inserted. If missing,
  415. // the XML is inserted whenever a new node of "itemType" is inserted. When present, the following fields further
  416. // qualify when the XML is inserted.
  417. //
  418. // matchItemAttribute - name of attribute from created node whose value is compared with the value of an attribute in
  419. // another node (defined by matchLocalAttribte and matchPath)
  420. // matchPath - XPath to select the node for comparing attribute values
  421. // matchLocalAttribute - name of attribute from node selected by matchPath for value comparison. This option is
  422. // optional. If not present, the name of the attribute for comparison in the selected node is
  423. // matchItemAttribute
  424. else if (it->first == "match")
  425. {
  426. std::string attrName = it->second.get("eventNodeAttribute", "").data();
  427. pInsert->setEventNodeAttributeName(attrName);
  428. std::string matchAttrName = it->second.get("targetAttribute", "");
  429. if (!matchAttrName.empty())
  430. {
  431. pInsert->setTargetAttributeName(matchAttrName);
  432. }
  433. std::string path = it->second.get("targetPath", "");
  434. pInsert->setTargetPath(path);
  435. }
  436. //
  437. // the XML to be inserted. It is inserted based on the match section
  438. else if (it->first == "xml")
  439. {
  440. pt::ptree emptyTree;
  441. const pt::ptree &insertXMLTree = it->second.get_child("", emptyTree);
  442. std::ostringstream out;
  443. pt::write_xml(out, insertXMLTree);
  444. pInsert->setEnvironmentInsertData(out.str());
  445. }
  446. }
  447. m_pSchemaItem->addEventHandler(pInsert);
  448. }
  449. //
  450. // addAttributeDependencies is used to set dependent values for an attribute based on the value of another attribute.
  451. else if (eventAction == "setAttributeValue")
  452. {
  453. std::shared_ptr<AttributeSetValueCreateEventHandler> pSetAttrValue = std::make_shared<AttributeSetValueCreateEventHandler>();
  454. pt::ptree dataTree = childTree.get_child("eventData", emptyTree);
  455. for (auto it = dataTree.begin(); it != dataTree.end(); ++it)
  456. {
  457. if (it->first == "itemType")
  458. {
  459. pSetAttrValue->setItemType(it->second.data());
  460. }
  461. else if (it->first == "attribute")
  462. {
  463. std::string attrName = getXSDAttributeValue(it->second, "<xmlattr>.attributeName");
  464. std::string attrVal = getXSDAttributeValue(it->second, "<xmlattr>.attributeValue");
  465. pSetAttrValue->addAttributeValue(attrName, attrVal);
  466. }
  467. else if (it->first == "match")
  468. {
  469. std::string attrName = it->second.get("eventNodeAttribute", "").data();
  470. pSetAttrValue->setEventNodeAttributeName(attrName);
  471. std::string matchAttrName = it->second.get("targetAttribute", "");
  472. if (!matchAttrName.empty())
  473. {
  474. pSetAttrValue->setTargetAttributeName(matchAttrName);
  475. }
  476. std::string path = it->second.get("targetPath", "");
  477. pSetAttrValue->setTargetPath(path);
  478. }
  479. }
  480. m_pSchemaItem->addEventHandler(pSetAttrValue);
  481. }
  482. }
  483. }
  484. }
  485. std::shared_ptr<SchemaType> XSDSchemaParser::getType(const pt::ptree &typeTree, bool nameRequired)
  486. {
  487. std::string typeName = getXSDAttributeValue(typeTree, "<xmlattr>.name", nameRequired, "");
  488. if (!nameRequired && !typeName.empty())
  489. {
  490. std::string msg = "Name (" + typeName + ") not allowed in local xs:simpleType definition";
  491. throw(ParseException(msg));
  492. }
  493. std::shared_ptr<SchemaType> pCfgType = std::make_shared<SchemaType>(typeName);
  494. std::shared_ptr<SchemaTypeLimits> pLimits;
  495. auto restriction = typeTree.find("xs:restriction");
  496. if (restriction != typeTree.not_found())
  497. {
  498. std::string xsdBaseType = getXSDAttributeValue(restriction->second, "<xmlattr>.base");
  499. std::shared_ptr<SchemaType> pBaseType = m_pSchemaItem->getSchemaValueType(xsdBaseType);
  500. pCfgType->setBaseType(pBaseType->getBaseType());
  501. if (typeName != pBaseType->getBaseType())
  502. {
  503. pCfgType->setSubType(typeName);
  504. }
  505. pLimits = pBaseType->getLimits();
  506. if (!restriction->second.empty())
  507. {
  508. pt::ptree restrictTree = restriction->second.get_child("", pt::ptree());
  509. if (std::dynamic_pointer_cast<SchemaTypeIntegerLimits>(pLimits) != nullptr)
  510. {
  511. std::shared_ptr<SchemaTypeIntegerLimits> pBaseIntLimits = std::dynamic_pointer_cast<SchemaTypeIntegerLimits>(pLimits);
  512. std::shared_ptr<SchemaTypeIntegerLimits> pIntLimits = std::make_shared<SchemaTypeIntegerLimits>(*pBaseIntLimits);
  513. parseIntegerTypeLimits(restrictTree, pIntLimits);
  514. pLimits = pIntLimits;
  515. }
  516. else if (std::dynamic_pointer_cast<SchemaTypeStringLimits>(pLimits) != nullptr)
  517. {
  518. std::shared_ptr<SchemaTypeStringLimits> pBaseStringimits = std::dynamic_pointer_cast<SchemaTypeStringLimits>(pLimits);
  519. std::shared_ptr<SchemaTypeStringLimits> pStringimits = std::make_shared<SchemaTypeStringLimits>(*pBaseStringimits);
  520. parseStringTypeLimits(restrictTree, pStringimits);
  521. pLimits = pStringimits;
  522. }
  523. else
  524. {
  525. std::string msg = "Unsupported base type(" + xsdBaseType + ")";
  526. throw(ParseException(msg));
  527. }
  528. }
  529. }
  530. pCfgType->setLimits(pLimits);
  531. return pCfgType;
  532. }
  533. void XSDSchemaParser::parseIntegerTypeLimits(const pt::ptree &restrictTree, std::shared_ptr<SchemaTypeIntegerLimits> &pIntegerLimits)
  534. {
  535. for (auto it = restrictTree.begin(); it != restrictTree.end(); ++it)
  536. {
  537. std::string restrictionType = it->first;
  538. if (restrictionType == "xs:minInclusive")
  539. pIntegerLimits->setMinInclusive(it->second.get<int>("<xmlattr>.value"));
  540. else if (restrictionType == "xs:maxInclusive")
  541. pIntegerLimits->setMaxInclusive(it->second.get<int>("<xmlattr>.value"));
  542. else if (restrictionType == "xs:minExclusive")
  543. pIntegerLimits->setMinExclusive(it->second.get<int>("<xmlattr>.value"));
  544. else if (restrictionType == "xs:maxExclusive")
  545. pIntegerLimits->setMaxExclusive(it->second.get<int>("<xmlattr>.value"));
  546. else if (restrictionType == "xs:enumeration")
  547. {
  548. parseAllowedValue(it->second, &(*pIntegerLimits));
  549. }
  550. else if (restrictionType != "<xmlattr>")
  551. {
  552. std::string msg = "Invalid restriction(" + it->first + ") found while parsing type";
  553. throw(ParseException(msg));
  554. }
  555. }
  556. }
  557. void XSDSchemaParser::parseStringTypeLimits(const pt::ptree &restrictTree, std::shared_ptr<SchemaTypeStringLimits> &pStringLimits)
  558. {
  559. for (auto it = restrictTree.begin(); it != restrictTree.end(); ++it)
  560. {
  561. std::string restrictionType = it->first;
  562. if (restrictionType == "xs:minLength")
  563. pStringLimits->setMinLength(it->second.get<int>("<xmlattr>.value"));
  564. else if (restrictionType == "xs:maxLength")
  565. pStringLimits->setMaxLength(it->second.get<int>("<xmlattr>.value"));
  566. else if (restrictionType == "xs:length")
  567. pStringLimits->setLength(it->second.get<int>("<xmlattr>.value"));
  568. else if (restrictionType == "xs:pattern")
  569. pStringLimits->addPattern(it->second.get("<xmlattr>.value", "0"));
  570. else if (restrictionType == "xs:enumeration")
  571. {
  572. parseAllowedValue(it->second, &(*pStringLimits));
  573. }
  574. else if (restrictionType != "<xmlattr>")
  575. {
  576. std::string msg = "Invalid restriction(" + it->first + ") found while parsing type";
  577. throw(ParseException(msg));
  578. }
  579. }
  580. }
  581. void XSDSchemaParser::parseAllowedValue(const pt::ptree &allowedValueTree, SchemaTypeLimits *pTypeLimits)
  582. {
  583. AllowedValue allowedValue;
  584. //
  585. // Parse the value for the enumeration, the add to the allowed values for the limits for this type. Note that enumerations
  586. // are enhanced with additional information for the UI.
  587. allowedValue.m_value = allowedValueTree.get("<xmlattr>.value", "XXXmissingYYY");
  588. allowedValue.m_displayName = allowedValueTree.get("<xmlattr>.hpcc:displayName", allowedValue.m_value);
  589. allowedValue.m_description = allowedValueTree.get("<xmlattr>.hpcc:description", "");
  590. allowedValue.m_userMessage = allowedValueTree.get("<xmlattr>.hpcc:userMessage", "");
  591. allowedValue.m_userMessageType = allowedValueTree.get("<xmlattr>.hpcc:userMessageType", allowedValue.m_userMessage.empty() ? "" : "info");
  592. //
  593. // Parse any attribute lists
  594. std::string attrList = allowedValueTree.get("<xmlattr>.hpcc:optionalAttributes", "");
  595. if (attrList.length())
  596. {
  597. allowedValue.m_optionalAttributes = splitString(attrList, ",");
  598. }
  599. attrList = allowedValueTree.get("<xmlattr>.hpcc:requiredAttributes", "");
  600. if (attrList.length())
  601. {
  602. allowedValue.m_requiredAttributes = splitString(attrList, ",");
  603. }
  604. //
  605. // Value is required. Throw an exception if not found
  606. if (allowedValue.m_value == "XXXmissingYYY")
  607. {
  608. std::string msg = "Missing value attribute for enumeration";
  609. throw(ParseException(msg));
  610. }
  611. pTypeLimits->addAllowedValue(allowedValue);
  612. }
  613. std::shared_ptr<SchemaValue> XSDSchemaParser::getSchemaValue(const pt::ptree &attr)
  614. {
  615. std::string attrName = getXSDAttributeValue(attr, "<xmlattr>.name");
  616. std::shared_ptr<SchemaValue> pCfgValue = std::make_shared<SchemaValue>(attrName);
  617. pCfgValue->setDisplayName(attr.get("<xmlattr>.hpcc:displayName", attrName));
  618. pCfgValue->setRequired(attr.get("<xmlattr>.use", "optional") == "required");
  619. pCfgValue->setTooltip(attr.get("<xmlattr>.hpcc:tooltip", ""));
  620. pCfgValue->setReadOnly(attr.get("<xmlattr>.hpcc:readOnly", "false") == "true");
  621. pCfgValue->setHidden(attr.get("<xmlattr>.hpcc:hidden", "false") == "true");
  622. pCfgValue->setDeprecated(attr.get("<xmlattr>.hpcc:deprecated", "false") == "true");
  623. pCfgValue->setMirrorFromPath(attr.get("<xmlattr>.hpcc:mirrorFrom", ""));
  624. pCfgValue->setAutoGenerateType(attr.get("<xmlattr>.hpcc:autoGenerateType", ""));
  625. pCfgValue->setAutoGenerateValue(attr.get("<xmlattr>.hpcc:autoGenerateValue", ""));
  626. pCfgValue->setDefaultValue(attr.get("<xmlattr>.default", ""));
  627. pCfgValue->setCodeDefault(attr.get("<xmlattr>.hpcc:defaultInCode", ""));
  628. pCfgValue->setValueLimitRuleType(attr.get("<xmlattr>.hpcc:valueLimitRuleType", ""));
  629. pCfgValue->setValueLimitRuleData(attr.get("<xmlattr>.hpcc:valueLimitRuleData", ""));
  630. pCfgValue->setRequiredIf(attr.get("<xmlattr>.hpcc:requiredIf", ""));
  631. std::string modList = attr.get("<xmlattr>.hpcc:modifiers", "");
  632. if (modList.length())
  633. {
  634. pCfgValue->setModifiers(splitString(modList, ","));
  635. }
  636. std::string typeName = attr.get("<xmlattr>.type", "");
  637. if (!typeName.empty())
  638. {
  639. pCfgValue->setType(m_pSchemaItem->getSchemaValueType(typeName));
  640. }
  641. else
  642. {
  643. std::shared_ptr<SchemaType> pType = getType(attr.get_child("xs:simpleType", pt::ptree()), false);
  644. if (!pType->isValid())
  645. {
  646. throw(ParseException("Attribute " + m_pSchemaItem->getProperty("name") + "[@" + attrName + "] does not have a valid type"));
  647. }
  648. pCfgValue->setType(pType);
  649. }
  650. //
  651. // Keyed value or from a keyed set?
  652. std::string uniqueKey = attr.get("<xmlattr>.hpcc:uniqueKey", "");
  653. std::string sourceKey = attr.get("<xmlattr>.hpcc:sourceKey", "");
  654. //
  655. // Make sure both aren't specified
  656. if (!uniqueKey.empty() && !sourceKey.empty())
  657. {
  658. throw(ParseException("Attribute " + m_pSchemaItem->getProperty("name") + "[@" + attrName + "] cannot be both unique and from a source path"));
  659. }
  660. //
  661. // If value must be unique, add a unique value set definition
  662. if (!uniqueKey.empty())
  663. {
  664. std::string elementPath = "./";
  665. m_pSchemaItem->addUniqueAttributeValueSetDefinition(uniqueKey, elementPath, attrName, true);
  666. }
  667. //
  668. // If the value must be from an existing attribute, add reference to such
  669. else if (!sourceKey.empty())
  670. {
  671. std::string elementPath = "./";
  672. m_pSchemaItem->addReferenceToUniqueAttributeValueSet(sourceKey, elementPath, attrName);
  673. }
  674. return pCfgValue;
  675. }