XSDSchemaParser.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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. namespace pt = boost::property_tree;
  22. bool XSDSchemaParser::doParse(const std::string &configPath, const std::string &masterConfigFile, const std::vector<std::string> &cfgParms)
  23. {
  24. bool rc = true;
  25. //
  26. // Add some default types to the config. Note changing values for limits
  27. std::shared_ptr<SchemaTypeStringLimits> pStringLimits;
  28. std::shared_ptr<SchemaTypeIntegerLimits> pIntLimits;
  29. std::shared_ptr<SchemaType> pType = std::make_shared<SchemaType>("xs:string");
  30. pStringLimits = std::make_shared<SchemaTypeStringLimits>();
  31. pType->setLimits(pStringLimits);
  32. m_pSchemaItem->addSchemaValueType(pType);
  33. pType = std::make_shared<SchemaType>("xs:token");
  34. pStringLimits = std::make_shared<SchemaTypeStringLimits>();
  35. pType->setLimits(pStringLimits);
  36. m_pSchemaItem->addSchemaValueType(pType);
  37. pType = std::make_shared<SchemaType>("xs:boolean");
  38. std::shared_ptr<SchemaTypeLimits> pBoolLimits = std::make_shared<SchemaTypeStringLimits>();
  39. pBoolLimits->addAllowedValue("true");
  40. pBoolLimits->addAllowedValue("false");
  41. pType->setLimits(pBoolLimits);
  42. m_pSchemaItem->addSchemaValueType(pType);
  43. pType = std::make_shared<SchemaType>("xs:integer");
  44. pIntLimits = std::make_shared<SchemaTypeIntegerLimits>();
  45. pType->setLimits(pIntLimits);
  46. m_pSchemaItem->addSchemaValueType(pType);
  47. pType = std::make_shared<SchemaType>("xs:int");
  48. pIntLimits = std::make_shared<SchemaTypeIntegerLimits>();
  49. pType->setLimits(pIntLimits);
  50. m_pSchemaItem->addSchemaValueType(pType);
  51. pType = std::make_shared<SchemaType>("xs:nonNegativeInteger");
  52. pIntLimits = std::make_shared<SchemaTypeIntegerLimits>();
  53. pIntLimits->setMinInclusive(0);
  54. pType->setLimits(pIntLimits);
  55. m_pSchemaItem->addSchemaValueType(pType);
  56. pType = std::make_shared<SchemaType>("xs:positiveInteger");
  57. pIntLimits = std::make_shared<SchemaTypeIntegerLimits>();
  58. pIntLimits->setMinInclusive(1);
  59. pType->setLimits(pIntLimits);
  60. m_pSchemaItem->addSchemaValueType(pType);
  61. pType = std::make_shared<SchemaType>("xs:unsignedInt");
  62. pIntLimits = std::make_shared<SchemaTypeIntegerLimits>();
  63. pIntLimits->setMinInclusive(0);
  64. pType->setLimits(pIntLimits);
  65. m_pSchemaItem->addSchemaValueType(pType);
  66. //
  67. // Get our specific XSD parameters from the input
  68. m_basePath = configPath;
  69. m_masterXSDFilename = masterConfigFile;
  70. //m_buildsetFilename = cfgParms[2];
  71. parseXSD(m_masterXSDFilename);
  72. return rc;
  73. }
  74. void XSDSchemaParser::parseXSD(const std::string &filename)
  75. {
  76. pt::ptree xsdTree;
  77. std::string fpath = m_basePath + filename;
  78. try
  79. {
  80. pt::read_xml(fpath, xsdTree, pt::xml_parser::trim_whitespace | pt::xml_parser::no_comments);
  81. }
  82. catch (const std::exception &e)
  83. {
  84. std::string xmlError = e.what();
  85. ParseException pe("Unable to read/parse file. Check that file is formatted correctly. Error = " + xmlError);
  86. pe.addFilename(filename);
  87. throw(pe);
  88. }
  89. try
  90. {
  91. auto schemaIt = xsdTree.find("xs:schema");
  92. pt::ptree emptyTree;
  93. const pt::ptree &keys = schemaIt->second.get_child("", emptyTree);
  94. parseXSD(keys);
  95. }
  96. catch (ParseException &pe)
  97. {
  98. pe.addFilename(filename);
  99. throw(pe);
  100. }
  101. }
  102. void XSDSchemaParser::parseXSD(const pt::ptree &keys)
  103. {
  104. for (auto it = keys.begin(); it != keys.end(); ++it)
  105. {
  106. //
  107. // Element parent (a type in realilty) and the element name help figure out how to process the XSD schema element
  108. std::string elemType = it->first;
  109. if (elemType == "xs:include")
  110. {
  111. std::string schemaFile = getXSDAttributeValue(it->second, "<xmlattr>.schemaLocation");
  112. if (m_pSchemaItem->addUniqueName(schemaFile))
  113. {
  114. parseXSD(schemaFile);
  115. }
  116. }
  117. else if (elemType == "xs:simpleType")
  118. {
  119. parseSimpleType(it->second);
  120. }
  121. else if (elemType == "xs:complexType")
  122. {
  123. parseComplexType(it->second);
  124. }
  125. else if (elemType == "xs:attributeGroup")
  126. {
  127. parseAttributeGroup(it->second);
  128. }
  129. else if (elemType == "xs:attribute")
  130. {
  131. parseAttribute(it->second);
  132. }
  133. else if (elemType == "xs:sequence")
  134. {
  135. parseXSD(it->second.get_child("", pt::ptree()));
  136. }
  137. else if (elemType == "xs:element")
  138. {
  139. parseElement(it->second);
  140. }
  141. else if (elemType == "xs:key")
  142. {
  143. parseKey(it->second);
  144. }
  145. else if (elemType == "xs:keyref")
  146. {
  147. parseKeyRef(it->second);
  148. }
  149. }
  150. }
  151. std::string XSDSchemaParser::getXSDAttributeValue(const pt::ptree &tree, const std::string &attrName, bool throwIfNotPresent, const std::string &defaultVal) const
  152. {
  153. std::string value = defaultVal;
  154. try
  155. {
  156. value = tree.get<std::string>(attrName);
  157. }
  158. catch (std::exception &e)
  159. {
  160. if (throwIfNotPresent)
  161. throw(ParseException("Missing attribute " + attrName + "."));
  162. }
  163. return value;
  164. }
  165. void XSDSchemaParser::parseSimpleType(const pt::ptree &typeTree)
  166. {
  167. std::shared_ptr<SchemaType> pCfgType = getSchemaType(typeTree, true);
  168. m_pSchemaItem->addSchemaValueType(pCfgType);
  169. }
  170. void XSDSchemaParser::parseAttribute(const pt::ptree &attr)
  171. {
  172. std::shared_ptr<SchemaValue> pCfgValue = getSchemaValue(attr);
  173. m_pSchemaItem->addAttribute(pCfgValue);
  174. }
  175. void XSDSchemaParser::parseAttributeGroup(const pt::ptree &attributeTree)
  176. {
  177. std::string groupName = getXSDAttributeValue(attributeTree, "<xmlattr>.name", false, ""); // only a named attributeGroup is supported
  178. //
  179. // 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
  180. // schema type that can be reused (usually with a ref= reference in another attribute group schema item)
  181. if (!groupName.empty())
  182. {
  183. std::shared_ptr<SchemaItem> pValueSet = std::make_shared<SchemaItem>(groupName, "valueset", m_pSchemaItem);
  184. std::shared_ptr<XSDValueSetParser> pXSDValueSetParaser = std::make_shared<XSDValueSetParser>(pValueSet);
  185. pXSDValueSetParaser->parseXSD(attributeTree.get_child("", pt::ptree()));
  186. m_pSchemaItem->addSchemaType(pValueSet, groupName);
  187. }
  188. //
  189. // Is it a reference to a named attribute group previously saved? If so, grab the defined attributes and add them.
  190. else
  191. {
  192. std::string refName = getXSDAttributeValue(attributeTree, "<xmlattr>.ref", false, ""); // only a named attributeGroup is supported
  193. if (!refName.empty())
  194. {
  195. std::shared_ptr<SchemaItem> pValueSet = m_pSchemaItem->getSchemaType(refName, true);
  196. if (pValueSet)
  197. {
  198. std::vector<std::shared_ptr<SchemaValue>> attributes;
  199. pValueSet->getAttributes(attributes);
  200. m_pSchemaItem->addAttribute(attributes);
  201. }
  202. }
  203. }
  204. }
  205. void XSDSchemaParser::parseComplexType(const pt::ptree &typeTree)
  206. {
  207. std::string complexTypeName = getXSDAttributeValue(typeTree, "<xmlattr>.name", false, "");
  208. std::string className = typeTree.get("<xmlattr>.hpcc:class", "");
  209. std::string catName = typeTree.get("<xmlattr>.hpcc:category", "");
  210. std::string componentName = typeTree.get("<xmlattr>.hpcc:componentName", "");
  211. std::string displayName = typeTree.get("<xmlattr>.hpcc:displayName", "");
  212. bool hidden = typeTree.get("<xmlattr>.hpcc:hidden", "false") == "true";
  213. if (!complexTypeName.empty())
  214. {
  215. if (!className.empty())
  216. {
  217. if (className == "component")
  218. {
  219. std::shared_ptr<SchemaItem> pComponent = std::make_shared<SchemaItem>(complexTypeName, "component", m_pSchemaItem);
  220. pComponent->setProperty("category", catName);
  221. pComponent->setProperty("componentName", componentName);
  222. pComponent->setProperty("displayName", displayName);
  223. pComponent->setHidden(hidden);
  224. pt::ptree componentTree = typeTree.get_child("", pt::ptree());
  225. if (!componentTree.empty())
  226. {
  227. std::shared_ptr<XSDComponentParser> pComponentXSDParaser = std::make_shared<XSDComponentParser>(std::dynamic_pointer_cast<SchemaItem>(pComponent));
  228. pComponentXSDParaser->parseXSD(typeTree);
  229. m_pSchemaItem->addSchemaType(pComponent, complexTypeName);
  230. }
  231. else
  232. {
  233. throw(ParseException("Component definition empty: " + displayName));
  234. }
  235. }
  236. else
  237. {
  238. throw(ParseException("Unrecognized class name for complex type: " + className));
  239. }
  240. }
  241. //
  242. // This is a complex type definition of just regular XSD statements, no special format. Create a parser and parse it
  243. // and add it to the
  244. else
  245. {
  246. std::shared_ptr<SchemaItem> pTypeItem = std::make_shared<SchemaItem>(complexTypeName, "", m_pSchemaItem);
  247. pt::ptree childTree = typeTree.get_child("", pt::ptree());
  248. if (!childTree.empty())
  249. {
  250. std::shared_ptr<XSDSchemaParser> pXSDParaser = std::make_shared<XSDSchemaParser>(pTypeItem);
  251. pXSDParaser->parseXSD(childTree);
  252. m_pSchemaItem->addSchemaType(pTypeItem, complexTypeName);
  253. }
  254. else
  255. {
  256. throw(ParseException("Complex type definition empty: " + displayName));
  257. }
  258. }
  259. }
  260. //
  261. // Just a complexType delimiter, ignore and parse the children
  262. else
  263. {
  264. parseXSD(typeTree.get_child("", pt::ptree()));
  265. }
  266. }
  267. void XSDSchemaParser::parseElement(const pt::ptree &elemTree)
  268. {
  269. std::string elementName = elemTree.get("<xmlattr>.name", "");
  270. std::string className = elemTree.get("<xmlattr>.hpcc:class", "");
  271. std::string category = elemTree.get("<xmlattr>.hpcc:category", "");
  272. std::string displayName = elemTree.get("<xmlattr>.hpcc:displayName", "");
  273. std::string tooltip = elemTree.get("<xmlattr>.hpcc:tooltip", "");
  274. std::string typeName = elemTree.get("<xmlattr>.type", "");
  275. unsigned minOccurs = elemTree.get("<xmlattr>.minOccurs", 1);
  276. std::string maxOccursStr = elemTree.get("<xmlattr>.maxOccurs", "1");
  277. unsigned maxOccurs = (maxOccursStr != "unbounded") ? stoi(maxOccursStr) : UINT_MAX;
  278. std::shared_ptr<SchemaItem> pNewSchemaItem = std::make_shared<SchemaItem>(elementName, className, m_pSchemaItem);
  279. pNewSchemaItem->setProperty("displayName", displayName);
  280. pNewSchemaItem->setMinInstances(minOccurs);
  281. pNewSchemaItem->setMaxInstances(maxOccurs);
  282. pNewSchemaItem->setProperty("category", category);
  283. pNewSchemaItem->setProperty("tooltip", tooltip);
  284. pNewSchemaItem->setHidden(elemTree.get("<xmlattr>.hpcc:hidden", "false") == "true");
  285. pt::ptree childTree = elemTree.get_child("", pt::ptree());
  286. // special case to set the root since the top level schema can't specify it
  287. if (category == "root") // special case to set the root since the top level schema can't specify it
  288. {
  289. m_pSchemaItem->setProperty("name", elementName);
  290. parseXSD(childTree);
  291. }
  292. else
  293. {
  294. //
  295. // If a type is specified, then either it's a simple value type (which could be previously defined) for this element, or a named complex type.
  296. if (!typeName.empty())
  297. {
  298. const std::shared_ptr<SchemaType> pSimpleType = m_pSchemaItem->getSchemaValueType(typeName, false);
  299. if (pSimpleType != nullptr)
  300. {
  301. std::shared_ptr<SchemaValue> pCfgValue = std::make_shared<SchemaValue>(""); // no name value since it's the element's value
  302. pCfgValue->setType(pSimpleType); // will throw if type is not defined
  303. pNewSchemaItem->setItemSchemaValue(pCfgValue);
  304. }
  305. else
  306. {
  307. std::shared_ptr<SchemaItem> pConfigType = m_pSchemaItem->getSchemaType(typeName, false);
  308. if (pConfigType != nullptr)
  309. {
  310. //
  311. // Insert into this config element the component defined data (attributes, references, etc.)
  312. pNewSchemaItem->insertSchemaType(pConfigType);
  313. //
  314. // Set element min/max instances to that defined by the component type def (ignore values parsed above)
  315. pNewSchemaItem->setMinInstances(pConfigType->getMinInstances());
  316. pNewSchemaItem->setMaxInstances(pConfigType->getMaxInstances());
  317. //
  318. // If a component, then set element data (allow overriding with locally parsed values)
  319. if (pConfigType->getProperty("className") == "component")
  320. {
  321. pNewSchemaItem->setProperty("name", (!elementName.empty()) ? elementName : pConfigType->getProperty("name"));
  322. pNewSchemaItem->setProperty("className", (!className.empty()) ? className : pConfigType->getProperty("className"));
  323. pNewSchemaItem->setProperty("category", (!category.empty()) ? category : pConfigType->getProperty("category"));
  324. pNewSchemaItem->setProperty("displayName", (!displayName.empty()) ? displayName : pConfigType->getProperty("displayName"));
  325. pNewSchemaItem->setProperty("componentName", pConfigType->getProperty("componentName"));
  326. }
  327. }
  328. else
  329. {
  330. std::string msg = "Unable to find type " + typeName + " when parsing element " + elementName;
  331. throw(ParseException(msg));
  332. }
  333. }
  334. }
  335. //
  336. // Now, if there are children, create a parser and have at it
  337. if (!childTree.empty())
  338. {
  339. std::shared_ptr<XSDSchemaParser> pXSDParaser = std::make_shared<XSDSchemaParser>(pNewSchemaItem);
  340. pXSDParaser->parseXSD(childTree);
  341. }
  342. //
  343. // Add the element
  344. m_pSchemaItem->addChild(pNewSchemaItem);
  345. }
  346. }
  347. std::shared_ptr<SchemaType> XSDSchemaParser::getSchemaType(const pt::ptree &typeTree, bool nameRequired)
  348. {
  349. std::string typeName = getXSDAttributeValue(typeTree, "<xmlattr>.name", nameRequired, "");
  350. std::shared_ptr<SchemaType> pCfgType = std::make_shared<SchemaType>(typeName);
  351. std::shared_ptr<SchemaTypeLimits> pLimits;
  352. auto restriction = typeTree.find("xs:restriction");
  353. if (restriction != typeTree.not_found())
  354. {
  355. std::string baseType = getXSDAttributeValue(restriction->second, "<xmlattr>.base");
  356. std::shared_ptr<SchemaType> pType = std::make_shared<SchemaType>(*(m_pSchemaItem->getSchemaValueType(baseType)));
  357. pLimits = pType->getLimits();
  358. if (!restriction->second.empty())
  359. {
  360. pt::ptree restrictTree = restriction->second.get_child("", pt::ptree());
  361. if (std::dynamic_pointer_cast<SchemaTypeIntegerLimits>(pLimits) != nullptr)
  362. {
  363. std::shared_ptr<SchemaTypeIntegerLimits> pBaseIntLimits = std::dynamic_pointer_cast<SchemaTypeIntegerLimits>(pLimits);
  364. std::shared_ptr<SchemaTypeIntegerLimits> pIntLimits = std::make_shared<SchemaTypeIntegerLimits>(*pBaseIntLimits);
  365. parseIntegerTypeLimits(restrictTree, pIntLimits);
  366. pLimits = pIntLimits;
  367. }
  368. else if (std::dynamic_pointer_cast<SchemaTypeStringLimits>(pLimits) != nullptr)
  369. {
  370. std::shared_ptr<SchemaTypeStringLimits> pBaseStringimits = std::dynamic_pointer_cast<SchemaTypeStringLimits>(pLimits);
  371. std::shared_ptr<SchemaTypeStringLimits> pStringimits = std::make_shared<SchemaTypeStringLimits>(*pBaseStringimits);
  372. parseStringTypeLimits(restrictTree, pStringimits);
  373. pLimits = pStringimits;
  374. }
  375. else
  376. {
  377. std::string msg = "Unsupported base type(" + baseType + ")";
  378. throw(ParseException(msg));
  379. }
  380. }
  381. }
  382. pCfgType->setLimits(pLimits);
  383. return pCfgType;
  384. }
  385. void XSDSchemaParser::parseIntegerTypeLimits(const pt::ptree &restrictTree, std::shared_ptr<SchemaTypeIntegerLimits> &pIntegerLimits)
  386. {
  387. for (auto it = restrictTree.begin(); it != restrictTree.end(); ++it)
  388. {
  389. std::string restrictionType = it->first;
  390. if (restrictionType == "xs:minInclusive")
  391. pIntegerLimits->setMinInclusive(it->second.get<int>("<xmlattr>.value"));
  392. else if (restrictionType == "xs:maxInclusive")
  393. pIntegerLimits->setMaxInclusive(it->second.get<int>("<xmlattr>.value"));
  394. else if (restrictionType == "xs:minExclusive")
  395. pIntegerLimits->setMinExclusive(it->second.get<int>("<xmlattr>.value"));
  396. else if (restrictionType == "xs:maxExclusive")
  397. pIntegerLimits->setMaxExclusive(it->second.get<int>("<xmlattr>.value"));
  398. else if (restrictionType == "xs:enumeration")
  399. {
  400. pIntegerLimits->addAllowedValue(it->second.get("<xmlattr>.value", "badbadbad"), it->second.get("<xmlattr>.hpcc:description", ""));
  401. }
  402. else if (restrictionType != "<xmlattr>")
  403. {
  404. std::string msg = "Invalid restriction(" + it->first + ") found while parsing type";
  405. throw(ParseException(msg));
  406. }
  407. }
  408. }
  409. void XSDSchemaParser::parseStringTypeLimits(const pt::ptree &restrictTree, std::shared_ptr<SchemaTypeStringLimits> &pStringLimits)
  410. {
  411. for (auto it = restrictTree.begin(); it != restrictTree.end(); ++it)
  412. {
  413. std::string restrictionType = it->first;
  414. if (restrictionType == "xs:minLength")
  415. pStringLimits->setMinLength(it->second.get<int>("<xmlattr>.value"));
  416. else if (restrictionType == "xs:maxLength")
  417. pStringLimits->setMaxLength(it->second.get<int>("<xmlattr>.value"));
  418. else if (restrictionType == "xs:length")
  419. pStringLimits->setLength(it->second.get<int>("<xmlattr>.value"));
  420. else if (restrictionType == "xs:pattern")
  421. pStringLimits->addPattern(it->second.get("<xmlattr>.value", "0"));
  422. else if (restrictionType == "xs:enumeration")
  423. {
  424. pStringLimits->addAllowedValue(it->second.get("<xmlattr>.value", "badbadbad"), it->second.get("<xmlattr>.hpcc:description", ""));
  425. }
  426. else if (restrictionType != "<xmlattr>")
  427. {
  428. std::string msg = "Invalid restriction(" + it->first + ") found while parsing type";
  429. throw(ParseException(msg));
  430. }
  431. }
  432. }
  433. std::shared_ptr<SchemaValue> XSDSchemaParser::getSchemaValue(const pt::ptree &attr)
  434. {
  435. std::string attrName = getXSDAttributeValue(attr, "<xmlattr>.name");
  436. std::shared_ptr<SchemaValue> pCfgValue = std::make_shared<SchemaValue>(attrName);
  437. pCfgValue->setDisplayName(attr.get("<xmlattr>.hpcc:displayName", attrName));
  438. pCfgValue->setRequired(attr.get("<xmlattr>.use", "optional") == "required");
  439. pCfgValue->setTooltip(attr.get("<xmlattr>.hpcc:tooltip", ""));
  440. pCfgValue->setReadOnly(attr.get("<xmlattr>.hpcc:readOnly", "false") == "true");
  441. pCfgValue->setHidden(attr.get("<xmlattr>.hpcc:hidden", "false") == "true");
  442. pCfgValue->setDeprecated(attr.get("<xmlattr>.hpcc:deprecated", "false") == "true");
  443. pCfgValue->setMirrorFromPath(attr.get("<xmlattr>.hpcc:mirrorFrom", ""));
  444. pCfgValue->setAutoGenerateType(attr.get("<xmlattr>.hpcc:autoGenerateType", ""));
  445. pCfgValue->setAutoGenerateValue(attr.get("<xmlattr>.hpcc:autoGenerateValue", ""));
  446. pCfgValue->setDefaultValue(attr.get("<xmlattr>.default", ""));
  447. std::string modList = attr.get("<xmlattr>.hpcc:modifiers", "");
  448. if (modList.length())
  449. {
  450. pCfgValue->setModifiers(split(modList, ","));
  451. }
  452. std::string typeName = attr.get("<xmlattr>.type", "");
  453. if (!typeName.empty())
  454. {
  455. pCfgValue->setType(m_pSchemaItem->getSchemaValueType(typeName));
  456. }
  457. else
  458. {
  459. std::shared_ptr<SchemaType> pType = getSchemaType(attr.get_child("xs:simpleType", pt::ptree()), false);
  460. if (!pType->isValid())
  461. {
  462. throw(ParseException("Attribute " + attrName + " does not have a valid type"));
  463. }
  464. pCfgValue->setType(pType);
  465. }
  466. return pCfgValue;
  467. }
  468. void XSDSchemaParser::parseKey(const pt::ptree &keyTree)
  469. {
  470. std::string keyName = getXSDAttributeValue(keyTree, "<xmlattr>.name");
  471. bool duplicateOk = keyTree.get("<xmlattr>.hpcc:allowDuplicate", "false") == "true";
  472. std::string elementName = getXSDAttributeValue(keyTree, "xs:selector.<xmlattr>.xpath", false, "");
  473. std::string attrName = getXSDAttributeValue(keyTree, "xs:field.<xmlattr>.xpath", false, "");
  474. std::string attributeName;
  475. if (attrName.find_first_of('@') != std::string::npos)
  476. {
  477. attributeName = attrName.substr(attrName.find_first_of('@') + 1);
  478. }
  479. else
  480. {
  481. attributeName = attrName;
  482. }
  483. m_pSchemaItem->addUniqueAttributeValueSetDefinition(keyName, elementName, attributeName, duplicateOk);
  484. }
  485. void XSDSchemaParser::parseKeyRef(const pt::ptree &keyTree)
  486. {
  487. std::string keyName = getXSDAttributeValue(keyTree, "<xmlattr>.refer");
  488. std::string elementName = getXSDAttributeValue(keyTree, "xs:selector.<xmlattr>.xpath", false, "");
  489. std::string attrName = getXSDAttributeValue(keyTree, "xs:field.<xmlattr>.xpath", false, "");
  490. std::string attributeName;
  491. if (attrName.find_first_of('@') != std::string::npos)
  492. {
  493. attributeName = attrName.substr(attrName.find_first_of('@') + 1);
  494. }
  495. else
  496. {
  497. attributeName = attrName;
  498. }
  499. m_pSchemaItem->addReferenceToUniqueAttributeValueSet(keyName, elementName, attributeName);
  500. }