public bool LoadSchema(string schemaXml, List<string> excludePaths) { if (excludePaths == null) excludePaths = new List<string>(); XDocument doc = XDocument.Parse(schemaXml); //set the root element and try to get a root element name _root = new SchemaElement(); var namespaceAttribute = doc.Root.Attribute(XName.Get("targetNamespace")); if (namespaceAttribute != null) _root.Namespace = namespaceAttribute.Value; else _root.Namespace = ""; _root.Root = _root; //recursively extract information about all child nodes foreach (XElement child in doc.Root.Elements()) processNodes(child, _root, excludePaths); explodeChildren(_root, "", null, 0); //find the real root - in syspro the root is actually a sub-node but some of the //schemas are actually incorrect. these schemas define child items in the root //but then instead of referencing in their correct location, they are defined again. //as a result, the only reliable way of determining the correct root is to use //the node with the highest number of children, evluated recursively if (_root.Name == "") { SchemaElement newRoot = null; int highestChildren = 0; foreach (KeyValuePair<string, SchemaElement> kvp in _root.Children) if (kvp.Value.TotalChildren > highestChildren) { newRoot = kvp.Value; highestChildren = kvp.Value.TotalChildren; } if (newRoot != null) _root = newRoot; } return true; }
public void ReplaceChild(SchemaElement element, string key) { RemoveChild(key); AddChild(element, key); }
/// <summary> /// Clones the current object but does not clone all child properties /// </summary> /// <returns></returns> public SchemaElement CreateDuplicate() { SchemaElement el = new SchemaElement() { Nillable = this.Nillable, MinOccurs = this.MinOccurs, MaxOccurs = this.MaxOccurs, MinLength = this.MinLength, MaxLength = this.MaxLength, EnumerationValues = this.EnumerationValues, DefaultValue = this.DefaultValue, //not cloned Attributes = this.Attributes, FieldType = this.FieldType, Name = this.Name, Reference = this.Reference, Documentation = this.Documentation, //not cloned Parent = this.Parent, //not cloned Root = this.Root, Namespace = this.Namespace, Children = new Dictionary<string, SchemaElement>() }; foreach (var child in this.Children) { var duplicateChild = child.Value.CreateDuplicate(); duplicateChild.Parent = el; el.Children.Add(child.Key, duplicateChild); } return el; }
public void AddChild(SchemaElement element, string key) { element.Parent = this; try { _children.Add(key, element); } catch (Exception ex) { throw new Exception(ex.Message + " (Key '" + key + "')"); } }
public void AddChild(SchemaElement element) { AddChild(element, element.Name); }
private void buildNodePath(SchemaElement element, ref string path) { path = element.Name + (path.Length == 0 ? "" : "/") + path; if (element.Parent != null) buildNodePath(element.Parent, ref path); }
private void processNodes(XElement node, SchemaElement curParent, List<string> excludePaths) { string partName = node.Name.LocalName.ToLower(); SchemaElement curEl; switch (partName) { case "element": curEl = new SchemaElement() { Root = _root, Name = (node.Attribute(XName.Get("name")) == null) ? "" : node.Attribute(XName.Get("name")).Value, Reference = node.Attribute(XName.Get("ref")) == null ? "" : node.Attribute(XName.Get("ref")).Value, DefaultValue = node.Attribute(XName.Get("default")) == null ? "" : node.Attribute(XName.Get("default")).Value, }; //changed assumption of "nillable" to true when not specified curEl.Nillable = node.Attribute(XName.Get("nillable")) == null ? false : ((node.Attribute(XName.Get("nillable")).Value.ToLower() == "true") || (node.Attribute(XName.Get("nillable")).Value == "1")); if (node.Attribute(XName.Get("minOccurs")) != null) { if (!Int32.TryParse(node.Attribute(XName.Get("minOccurs")).Value, out curEl.MinOccurs)) curEl.MinOccurs = SchemaElement.UndefinedValue; } if (node.Attribute(XName.Get("maxOccurs")) != null) { if (!Int32.TryParse(node.Attribute(XName.Get("maxOccurs")).Value, out curEl.MaxOccurs)) curEl.MaxOccurs = SchemaElement.UndefinedValue; } string type = node.Attribute(XName.Get("type")) == null ? "" : node.Attribute(XName.Get("type")).Value; curEl.FieldType = type.IndexOf(":") > -1 ? type.Substring(type.IndexOf(":") + 1) : type; if ((curEl.Reference == "") && (type.Length > 0) && (type.IndexOf(":") == -1)) curEl.Reference = type; //cache all attributes curEl.Attributes = node.Attributes(); //apply exclusion paths if (excludePaths.Contains(getNodePath(curParent) + "/" + curEl.Name)) return; curParent.AddChild(curEl); //process all child elements - curEl is the parent foreach (XElement childNode in node.Elements()) processNodes(childNode, curEl, excludePaths); break; case "complextype": // 2015/09/02 - allowing simple types to be declared as references too case "simpletype": if (node.Attribute(XName.Get("name")) == null) { foreach (XElement childNode in node.Elements()) processNodes(childNode, curParent, excludePaths); } else { curEl = new SchemaElement() { Root = _root, Name = (node.Attribute(XName.Get("name")) == null) ? "" : node.Attribute(XName.Get("name")).Value, }; //apply exclusion paths if (excludePaths.Contains(getNodePath(curParent) + "/" + curEl.Name)) return; curParent.AddChild(curEl); //process all child elements - curEl is the parent foreach (XElement childNode in node.Elements()) processNodes(childNode, curEl, excludePaths); } break; case "documentation": //write documentation for the current parent curParent.Documentation = cleanDocumentation(node.Value); break; case "enumeration": if (node.Attribute(XName.Get("value")) != null) curParent.EnumerationValues.Add(node.Attribute(XName.Get("value")).Value); break; case "minlength": if ((node.Parent.Name.LocalName.ToLower().EndsWith("restriction")) && (node.Attribute(XName.Get("value")) != null)) { if (!Int32.TryParse(node.Attribute(XName.Get("value")).Value, out curParent.MinLength)) curParent.MinLength = SchemaElement.UndefinedValue; } break; case "maxlength": if ((node.Parent.Name.LocalName.ToLower().EndsWith("restriction")) && (node.Attribute(XName.Get("value")) != null)) { if (!Int32.TryParse(node.Attribute(XName.Get("value")).Value, out curParent.MaxLength)) curParent.MaxLength = SchemaElement.UndefinedValue; } break; } if ((partName == "annotation") || (partName == "restriction") || (partName == "sequence") || (partName == "all")) { foreach (XElement childNode in node.Elements()) processNodes(childNode, curParent, excludePaths); } }
private string getNodePath(SchemaElement element) { string path = ""; buildNodePath(element, ref path); return path; }
private void explodeChildren(SchemaElement element, string elementKey, SchemaElement parent, int currentDepth) { if (currentDepth >= MAX_SCHEMA_DEPTH) return; foreach (var child in new Dictionary<string, SchemaElement>(element.Children)) { SchemaElement childElement = child.Value; if (childElement.IsReference) { if (!_root.Children.ContainsKey(childElement.Reference)) throw new Exception("Referenced element '" + childElement.Reference + "' is not defined!"); if (_root.Children[childElement.Reference].IsReference) throw new Exception("Referenced element '" + childElement.Reference + "' is a reference!"); //remove self and add the referenced item instead childElement = _root.Children[childElement.Reference].CreateDuplicate(); childElement.Parent = element; childElement.Name = child.Key; element.ReplaceChild(childElement, child.Key); } explodeChildren(childElement, child.Key, element, currentDepth + 1); } }