726 content_value.append({"name": element_infos["name"], "value": value}) |
683 content_value.append({"name": element_infos["name"], "value": value}) |
727 else: |
684 else: |
728 content_value = GetElementInitialValue(factory, infos) |
685 content_value = GetElementInitialValue(factory, infos) |
729 return {"name": content_name, "value": content_value} |
686 return {"name": content_name, "value": content_value} |
730 |
687 |
731 def CheckContent(value): |
|
732 if value["name"] != "sequence": |
|
733 infos = choices_dict.get(value["name"], None) |
|
734 if infos is not None: |
|
735 return CheckElementValue(factory, value["name"], infos, value["value"], False) |
|
736 elif len(value["value"]) > 0: |
|
737 infos = choices_dict.get(value["value"][0]["name"], None) |
|
738 if infos is None: |
|
739 for choice_name, infos in choices: |
|
740 if infos["type"] == "sequence": |
|
741 for element_infos in infos["elements"]: |
|
742 if element_infos["type"] == CHOICE: |
|
743 infos = GetContentInfos(value["value"][0]["name"], element_infos["choices"]) |
|
744 if infos is not None: |
|
745 sequence_number = 0 |
|
746 element_idx = 0 |
|
747 while element_idx < len(value["value"]): |
|
748 for element_infos in infos["elements"]: |
|
749 element_value = None |
|
750 if element_infos["type"] == CHOICE: |
|
751 choice_infos = None |
|
752 if element_idx < len(value["value"]): |
|
753 for choice in element_infos["choices"]: |
|
754 if choice["name"] == value["value"][element_idx]["name"]: |
|
755 choice_infos = choice |
|
756 element_value = value["value"][element_idx]["value"] |
|
757 element_idx += 1 |
|
758 break |
|
759 if ((choice_infos is not None and |
|
760 not CheckElementValue(factory, choice_infos["name"], choice_infos, element_value, False)) or |
|
761 (choice_infos is None and element_infos["minOccurs"] > 0)): |
|
762 raise ValueError("Invalid sequence value in attribute 'content'") |
|
763 else: |
|
764 if element_idx < len(value["value"]) and element_infos["name"] == value["value"][element_idx]["name"]: |
|
765 element_value = value["value"][element_idx]["value"] |
|
766 element_idx += 1 |
|
767 if not CheckElementValue(factory, element_infos["name"], element_infos, element_value, False): |
|
768 raise ValueError("Invalid sequence value in attribute 'content'") |
|
769 sequence_number += 1 |
|
770 if sequence_number < infos["minOccurs"] or infos["maxOccurs"] != "unbounded" and sequence_number > infos["maxOccurs"]: |
|
771 raise ValueError("Invalid sequence value in attribute 'content'") |
|
772 return True |
|
773 else: |
|
774 for element_name, infos in choices: |
|
775 if element_name == "sequence": |
|
776 required = 0 |
|
777 for element in infos["elements"]: |
|
778 if element["minOccurs"] > 0: |
|
779 required += 1 |
|
780 if required == 0: |
|
781 return True |
|
782 return False |
|
783 |
|
784 def ExtractContent(tree, content): |
|
785 infos = choices_dict.get(tree.nodeName, None) |
|
786 if infos is not None: |
|
787 if infos["name"] == "sequence": |
|
788 sequence_dict = dict([(element_infos["name"], element_infos) for element_infos in infos["elements"] if element_infos["type"] != CHOICE]) |
|
789 element_infos = sequence_dict.get(tree.nodeName) |
|
790 if content is not None and \ |
|
791 content["name"] == "sequence" and \ |
|
792 len(content["value"]) > 0 and \ |
|
793 choices_dict.get(content["value"][-1]["name"]) == infos: |
|
794 return {"name": "sequence", |
|
795 "value": content["value"] + [ExtractContentElement(factory, tree, element_infos, content["value"][-1])]} |
|
796 else: |
|
797 return {"name": "sequence", |
|
798 "value": [ExtractContentElement(factory, tree, element_infos, None)]} |
|
799 else: |
|
800 return ExtractContentElement(factory, tree, infos, content) |
|
801 else: |
|
802 for choice_name, infos in choices: |
|
803 if infos["type"] == "sequence": |
|
804 for element_infos in infos["elements"]: |
|
805 if element_infos["type"] == CHOICE: |
|
806 try: |
|
807 if content is not None and \ |
|
808 content["name"] == "sequence" and \ |
|
809 len(content["value"]) > 0: |
|
810 return {"name": "sequence", |
|
811 "value": content["value"] + [element_infos["elmt_type"]["extract"](tree, content["value"][-1])]} |
|
812 else: |
|
813 return {"name": "sequence", |
|
814 "value": [element_infos["elmt_type"]["extract"](tree, None)]} |
|
815 except: |
|
816 pass |
|
817 raise ValueError("Invalid element \"%s\" for content!" % tree.nodeName) |
|
818 |
|
819 def GenerateContent(value, name=None, indent=0): |
|
820 text = "" |
|
821 if value["name"] != "sequence": |
|
822 infos = choices_dict.get(value["name"], None) |
|
823 if infos is not None: |
|
824 infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"]) |
|
825 if infos["maxOccurs"] == "unbounded" or infos["maxOccurs"] > 1: |
|
826 for item in value["value"]: |
|
827 text += infos["elmt_type"]["generate"](item, value["name"], indent) |
|
828 else: |
|
829 text += infos["elmt_type"]["generate"](value["value"], value["name"], indent) |
|
830 elif len(value["value"]) > 0: |
|
831 infos = choices_dict.get(value["value"][0]["name"], None) |
|
832 if infos is None: |
|
833 for choice_name, infos in choices: |
|
834 if infos["type"] == "sequence": |
|
835 for element_infos in infos["elements"]: |
|
836 if element_infos["type"] == CHOICE: |
|
837 infos = GetContentInfos(value["value"][0]["name"], element_infos["choices"]) |
|
838 if infos is not None: |
|
839 sequence_dict = dict([(element_infos["name"], element_infos) for element_infos in infos["elements"]]) |
|
840 for element_value in value["value"]: |
|
841 element_infos = sequence_dict.get(element_value["name"]) |
|
842 if element_infos["maxOccurs"] == "unbounded" or element_infos["maxOccurs"] > 1: |
|
843 for item in element_value["value"]: |
|
844 text += element_infos["elmt_type"]["generate"](item, element_value["name"], indent) |
|
845 else: |
|
846 text += element_infos["elmt_type"]["generate"](element_value["value"], element_infos["name"], indent) |
|
847 return text |
|
848 |
|
849 return { |
688 return { |
850 "type": COMPLEXTYPE, |
689 "type": COMPLEXTYPE, |
851 "choices_xpath": GetContentChoicesXPath, |
690 "choices_xpath": GetContentChoicesXPath, |
852 "initial": GetContentInitial, |
691 "initial": GetContentInitial, |
853 "check": CheckContent, |
|
854 "extract": ExtractContent, |
|
855 "generate": GenerateContent |
|
856 } |
692 } |
857 |
693 |
858 #------------------------------------------------------------------------------- |
694 #------------------------------------------------------------------------------- |
859 # Structure extraction functions |
695 # Structure extraction functions |
860 #------------------------------------------------------------------------------- |
696 #------------------------------------------------------------------------------- |
1298 classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname) |
1134 classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname) |
1299 classmembers["set%s" % elmtname] = generateSetMethod(elmtname) |
1135 classmembers["set%s" % elmtname] = generateSetMethod(elmtname) |
1300 classmembers["get%s" % elmtname] = generateGetMethod(elmtname) |
1136 classmembers["get%s" % elmtname] = generateGetMethod(elmtname) |
1301 |
1137 |
1302 classmembers["init"] = generateInitMethod(self, classinfos) |
1138 classmembers["init"] = generateInitMethod(self, classinfos) |
1303 classmembers["getStructure"] = generateStructureMethod(classinfos) |
|
1304 classmembers["loadXMLTree"] = generateLoadXMLTree(self, classinfos) |
|
1305 classmembers["generateXMLText"] = generateGenerateXMLText(self, classinfos) |
|
1306 classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos) |
1139 classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos) |
1307 classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos) |
1140 classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos) |
1308 classmembers["setElementValue"] = generateSetElementValue(self, classinfos) |
1141 classmembers["setElementValue"] = generateSetElementValue(self, classinfos) |
1309 classmembers["singleLineAttributes"] = True |
|
1310 classmembers["compatibility"] = lambda x, y: None |
|
1311 classmembers["extraAttrs"] = {} |
|
1312 |
1142 |
1313 class_definition = classobj(str(classname), bases, classmembers) |
1143 class_definition = classobj(str(classname), bases, classmembers) |
1314 setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos)) |
1144 setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos)) |
1315 setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos)) |
1145 setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos)) |
1316 class_infos = {"type": COMPILEDCOMPLEXTYPE, |
1146 class_infos = {"type": COMPILEDCOMPLEXTYPE, |
1317 "name": classname, |
1147 "name": classname, |
1318 "check": generateClassCheckFunction(class_definition), |
|
1319 "initial": generateClassCreateFunction(class_definition), |
1148 "initial": generateClassCreateFunction(class_definition), |
1320 "extract": generateClassExtractFunction(class_definition), |
1149 } |
1321 "generate": class_definition.generateXMLText} |
|
1322 |
1150 |
1323 if self.FileName is not None: |
1151 if self.FileName is not None: |
1324 self.ComputedClasses[self.FileName][classname] = class_definition |
1152 self.ComputedClasses[self.FileName][classname] = class_definition |
1325 else: |
1153 else: |
1326 self.ComputedClasses[classname] = class_definition |
1154 self.ComputedClasses[classname] = class_definition |
1480 self.insert(insertion_point, element) |
1286 self.insert(insertion_point, element) |
1481 |
1287 |
1482 elif classinfos.has_key("base"): |
1288 elif classinfos.has_key("base"): |
1483 return classinfos["base"].__setattr__(self, name, value) |
1289 return classinfos["base"].__setattr__(self, name, value) |
1484 |
1290 |
1485 elif class_definition.__dict__.has_key(name): |
|
1486 return DefaultElementClass.__setattr__(self, name, value) |
|
1487 |
|
1488 else: |
1291 else: |
1489 raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name)) |
1292 raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name)) |
1490 |
1293 |
1491 return setattrMethod |
1294 return setattrMethod |
1492 |
|
1493 """ |
|
1494 Method that generate the method for generating the xml tree structure model by |
|
1495 following the attributes list defined |
|
1496 """ |
|
1497 def ComputeMultiplicity(name, infos): |
|
1498 if infos["minOccurs"] == 0: |
|
1499 if infos["maxOccurs"] == "unbounded": |
|
1500 return "(?:%s)*" % name |
|
1501 elif infos["maxOccurs"] == 1: |
|
1502 return "(?:%s)?" % name |
|
1503 else: |
|
1504 return "(?:%s){,%d}" % (name, infos["maxOccurs"]) |
|
1505 elif infos["minOccurs"] == 1: |
|
1506 if infos["maxOccurs"] == "unbounded": |
|
1507 return "(?:%s)+" % name |
|
1508 elif infos["maxOccurs"] == 1: |
|
1509 return "(?:%s)" % name |
|
1510 else: |
|
1511 return "(?:%s){1,%d}" % (name, infos["maxOccurs"]) |
|
1512 else: |
|
1513 if infos["maxOccurs"] == "unbounded": |
|
1514 return "(?:%s){%d,}" % (name, infos["minOccurs"], name) |
|
1515 else: |
|
1516 return "(?:%s){%d,%d}" % (name, infos["minOccurs"], |
|
1517 infos["maxOccurs"]) |
|
1518 |
|
1519 def GetStructure(classinfos): |
|
1520 elements = [] |
|
1521 for element in classinfos["elements"]: |
|
1522 if element["type"] == ANY: |
|
1523 infos = element.copy() |
|
1524 infos["minOccurs"] = 0 |
|
1525 elements.append(ComputeMultiplicity("#text |#cdata-section |\w* ", infos)) |
|
1526 elif element["type"] == CHOICE: |
|
1527 choices = [] |
|
1528 for infos in element["choices"]: |
|
1529 if infos["type"] == "sequence": |
|
1530 structure = "(?:%s)" % GetStructure(infos) |
|
1531 else: |
|
1532 structure = "%s " % infos["name"] |
|
1533 choices.append(ComputeMultiplicity(structure, infos)) |
|
1534 elements.append(ComputeMultiplicity("|".join(choices), element)) |
|
1535 elif element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE: |
|
1536 elements.append("(?:#text |#cdata-section )?") |
|
1537 else: |
|
1538 elements.append(ComputeMultiplicity("%s " % element["name"], element)) |
|
1539 if classinfos.get("order", True) or len(elements) == 0: |
|
1540 return "".join(elements) |
|
1541 else: |
|
1542 raise ValueError("XSD structure not yet supported!") |
|
1543 |
|
1544 def generateStructureMethod(classinfos): |
|
1545 def getStructureMethod(self): |
|
1546 structure = GetStructure(classinfos) |
|
1547 if classinfos.has_key("base"): |
|
1548 return classinfos["base"].getStructure(self) + structure |
|
1549 return structure |
|
1550 return getStructureMethod |
|
1551 |
|
1552 """ |
|
1553 Method that generate the method for loading an xml tree by following the |
|
1554 attributes list defined |
|
1555 """ |
|
1556 def generateLoadXMLTree(factory, classinfos): |
|
1557 attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) |
|
1558 elements = dict([(element["name"], element) for element in classinfos["elements"]]) |
|
1559 |
|
1560 def loadXMLTreeMethod(self, tree, extras=[], derived=False): |
|
1561 self.extraAttrs = {} |
|
1562 self.compatibility(tree) |
|
1563 if not derived: |
|
1564 children_structure = "" |
|
1565 for node in tree.childNodes: |
|
1566 if not (node.nodeName == "#text" and node.data.strip() == "") and node.nodeName != "#comment": |
|
1567 children_structure += "%s " % node.nodeName |
|
1568 structure_pattern = self.getStructure() |
|
1569 if structure_pattern != "": |
|
1570 structure_model = re.compile("(%s)$" % structure_pattern) |
|
1571 result = structure_model.match(children_structure) |
|
1572 if not result: |
|
1573 raise ValueError("Invalid structure for \"%s\" children!." % tree.nodeName) |
|
1574 required_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "required"]) |
|
1575 if classinfos.has_key("base"): |
|
1576 extras.extend([attr["name"] for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) |
|
1577 classinfos["base"].loadXMLTree(self, tree, extras, True) |
|
1578 for attrname, attr in tree._attrs.iteritems(): |
|
1579 if attributes.has_key(attrname): |
|
1580 attributes[attrname]["attr_type"] = FindTypeInfos(factory, attributes[attrname]["attr_type"]) |
|
1581 object.__setattr__(self, attrname, attributes[attrname]["attr_type"]["extract"](attr)) |
|
1582 elif not classinfos.has_key("base") and not attrname in extras and not self.extraAttrs.has_key(attrname): |
|
1583 self.extraAttrs[attrname] = GetAttributeValue(attr) |
|
1584 required_attributes.pop(attrname, None) |
|
1585 if len(required_attributes) > 0: |
|
1586 raise ValueError("Required attributes %s missing for \"%s\" element!" % (", ".join(["\"%s\""%name for name in required_attributes]), tree.nodeName)) |
|
1587 first = {} |
|
1588 for node in tree.childNodes: |
|
1589 name = node.nodeName |
|
1590 if name == "#text" and node.data.strip() == "" or name == "#comment": |
|
1591 continue |
|
1592 elif elements.has_key(name): |
|
1593 elements[name]["elmt_type"] = FindTypeInfos(factory, elements[name]["elmt_type"]) |
|
1594 if elements[name]["maxOccurs"] == "unbounded" or elements[name]["maxOccurs"] > 1: |
|
1595 if first.get(name, True): |
|
1596 object.__setattr__(self, name, [elements[name]["elmt_type"]["extract"](node)]) |
|
1597 first[name] = False |
|
1598 else: |
|
1599 getattr(self, name).append(elements[name]["elmt_type"]["extract"](node)) |
|
1600 else: |
|
1601 object.__setattr__(self, name, elements[name]["elmt_type"]["extract"](node)) |
|
1602 elif elements.has_key("text"): |
|
1603 if elements["text"]["maxOccurs"] == "unbounded" or elements["text"]["maxOccurs"] > 1: |
|
1604 if first.get("text", True): |
|
1605 object.__setattr__(self, "text", [elements["text"]["elmt_type"]["extract"](node)]) |
|
1606 first["text"] = False |
|
1607 else: |
|
1608 getattr(self, "text").append(elements["text"]["elmt_type"]["extract"](node)) |
|
1609 else: |
|
1610 object.__setattr__(self, "text", elements["text"]["elmt_type"]["extract"](node)) |
|
1611 elif elements.has_key("content"): |
|
1612 if name in ["#cdata-section", "#text"]: |
|
1613 if elements["content"]["elmt_type"]["type"] == SIMPLETYPE: |
|
1614 object.__setattr__(self, "content", elements["content"]["elmt_type"]["extract"](node.data, False)) |
|
1615 else: |
|
1616 content = getattr(self, "content") |
|
1617 if elements["content"]["maxOccurs"] == "unbounded" or elements["content"]["maxOccurs"] > 1: |
|
1618 if first.get("content", True): |
|
1619 object.__setattr__(self, "content", [elements["content"]["elmt_type"]["extract"](node, None)]) |
|
1620 first["content"] = False |
|
1621 else: |
|
1622 content.append(elements["content"]["elmt_type"]["extract"](node, content)) |
|
1623 else: |
|
1624 object.__setattr__(self, "content", elements["content"]["elmt_type"]["extract"](node, content)) |
|
1625 return loadXMLTreeMethod |
|
1626 |
|
1627 |
|
1628 """ |
|
1629 Method that generates the method for generating an xml text by following the |
|
1630 attributes list defined |
|
1631 """ |
|
1632 def generateGenerateXMLText(factory, classinfos): |
|
1633 def generateXMLTextMethod(self, name, indent=0, extras={}, derived=False): |
|
1634 ind1, ind2 = getIndent(indent, name) |
|
1635 if not derived: |
|
1636 text = ind1 + u'<%s' % name |
|
1637 else: |
|
1638 text = u'' |
|
1639 |
|
1640 first = True |
|
1641 |
|
1642 if not classinfos.has_key("base"): |
|
1643 extras.update(self.extraAttrs) |
|
1644 for attr, value in extras.iteritems(): |
|
1645 if not first and not self.singleLineAttributes: |
|
1646 text += u'\n%s' % (ind2) |
|
1647 text += u' %s=%s' % (attr, quoteattr(value)) |
|
1648 first = False |
|
1649 extras.clear() |
|
1650 for attr in classinfos["attributes"]: |
|
1651 if attr["use"] != "prohibited": |
|
1652 attr["attr_type"] = FindTypeInfos(factory, attr["attr_type"]) |
|
1653 value = getattr(self, attr["name"], None) |
|
1654 if value != None: |
|
1655 computed_value = attr["attr_type"]["generate"](value) |
|
1656 else: |
|
1657 computed_value = None |
|
1658 if attr["use"] != "optional" or (value != None and \ |
|
1659 computed_value != attr.get("default", attr["attr_type"]["generate"](attr["attr_type"]["initial"]()))): |
|
1660 if classinfos.has_key("base"): |
|
1661 extras[attr["name"]] = computed_value |
|
1662 else: |
|
1663 if not first and not self.singleLineAttributes: |
|
1664 text += u'\n%s' % (ind2) |
|
1665 text += ' %s=%s' % (attr["name"], quoteattr(computed_value)) |
|
1666 first = False |
|
1667 if classinfos.has_key("base"): |
|
1668 first, new_text = classinfos["base"].generateXMLText(self, name, indent, extras, True) |
|
1669 text += new_text |
|
1670 else: |
|
1671 first = True |
|
1672 for element in classinfos["elements"]: |
|
1673 element["elmt_type"] = FindTypeInfos(factory, element["elmt_type"]) |
|
1674 value = getattr(self, element["name"], None) |
|
1675 if element["minOccurs"] == 0 and element["maxOccurs"] == 1: |
|
1676 if value is not None: |
|
1677 if first: |
|
1678 text += u'>\n' |
|
1679 first = False |
|
1680 text += element["elmt_type"]["generate"](value, element["name"], indent + 1) |
|
1681 elif element["minOccurs"] == 1 and element["maxOccurs"] == 1: |
|
1682 if first: |
|
1683 text += u'>\n' |
|
1684 first = False |
|
1685 if element["name"] == "content" and element["elmt_type"]["type"] == SIMPLETYPE: |
|
1686 text += element["elmt_type"]["generate"](value) |
|
1687 else: |
|
1688 text += element["elmt_type"]["generate"](value, element["name"], indent + 1) |
|
1689 else: |
|
1690 if first and len(value) > 0: |
|
1691 text += u'>\n' |
|
1692 first = False |
|
1693 for item in value: |
|
1694 text += element["elmt_type"]["generate"](item, element["name"], indent + 1) |
|
1695 if not derived: |
|
1696 if first: |
|
1697 text += u'/>\n' |
|
1698 else: |
|
1699 text += ind1 + u'</%s>\n' % (name) |
|
1700 return text |
|
1701 else: |
|
1702 return first, text |
|
1703 return generateXMLTextMethod |
|
1704 |
1295 |
1705 def gettypeinfos(name, facets): |
1296 def gettypeinfos(name, facets): |
1706 if facets.has_key("enumeration") and facets["enumeration"][0] is not None: |
1297 if facets.has_key("enumeration") and facets["enumeration"][0] is not None: |
1707 return facets["enumeration"][0] |
1298 return facets["enumeration"][0] |
1708 elif facets.has_key("maxInclusive"): |
1299 elif facets.has_key("maxInclusive"): |