private void BeginProperty(XmlReader reader) { StackFrame topFrame = stack.Peek(); EntityPropertyInfo entityPropertyInfo = topFrame.entity.Properties[reader.LocalName]; if (!topFrame.dynamic) { // Assumptions: // - expecting property to match exactly XML element name // - only public members looked for // Improvement: // - Process this validation when the metadata has been processed. PropertyInfo property = topFrame.instanceType.GetProperty(reader.LocalName); if (property == null) { throw new InvalidOperationException(string.Format("Property {0} does not exist on typeName {1}", reader.LocalName, topFrame.instanceType.Name)); } // Assumptions: // - No type conversion is performed to assign the variable // Improvements: // - Process this validation when the metadata has been processed. if (!property.PropertyType.IsAssignableFrom(entityPropertyInfo.Type)) { throw new InvalidOperationException(string.Format("Property {0} cannot be assigned from type {1}", reader.LocalName, entityInfo.Properties[reader.LocalName].TypeName)); } StackFrame frame = topFrame.Clone(); frame.elementName = XmlConvert.DecodeName(reader.LocalName); frame.property = property; frame.entityPropertyInfo = entityPropertyInfo; frame.state = state; stack.Push(frame); } else { StackFrame frame = topFrame.Clone(); frame.elementName = XmlConvert.DecodeName(reader.LocalName); frame.entityPropertyInfo = entityPropertyInfo; frame.state = state; if (hasAddMethod) { frame.iAddInstance = (IEntityPropertySetter)frame.instance; } else { MethodInfo addMethod = topFrame.instanceType.GetMethod("Add"); frame.addMethod = addMethod; } stack.Push(frame); } if (entityPropertyInfo.IsArray) { state = ParserState.ArrayProperty; if (reader.IsEmptyElement) { EndArrayProperty(reader); } } else { state = ParserState.Property; if (reader.IsEmptyElement) { ProcessPropertyValue(reader); EndProperty(reader); } } }
public T ReadNextEntity(XmlReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (this.state) { case ParserState.Start: // Assumption: // - skip the soap response tags if ((reader.LocalName == "QueryXmlResponse") || (reader.LocalName == "QueryXmlResult")) { continue; } if (string.CompareOrdinal(reader.LocalName, "queryResult") == 0) { this.state = ParserState.Root; } else { throw new InvalidOperationException("Expecting <queryResult> element but found " + reader.LocalName); } break; case ParserState.Root: if (string.CompareOrdinal(reader.LocalName, "template") == 0) { state = ParserState.Template; } else if (string.CompareOrdinal(reader.LocalName, "data") == 0) { if (entityInfo == null) { throw new InvalidOperationException("No root entity was defined in the template section"); } state = ParserState.Data; } else { throw new InvalidOperationException("Unexepected element " + reader.LocalName); } break; case ParserState.Template: if (string.CompareOrdinal(reader.LocalName, "entity") == 0) { if (entityInfo != null) { throw new InvalidOperationException("Only one root entity is supported at this time"); } StackFrame state = new StackFrame(); state.entity = new EntityInfo(reader["name"], reader["type"], bool.Parse(reader["dynamic"])); stack.Push(state); entityInfo = state.entity; this.state = ParserState.EntityTemplate; } break; case ParserState.EntityTemplate: if (string.CompareOrdinal(reader.LocalName, "property") == 0) { var name = reader["name"]; var entity = stack.Peek().entity; entity.Properties.Add(XmlConvert.DecodeName(name), new EntityPropertyInfo(name, reader["type"])); // Sometime empty elements come with an end element, adjust the statemachine state accordingly if (!reader.IsEmptyElement) { state = ParserState.PropertyTemplate; } } else if (string.CompareOrdinal(reader.LocalName, "entity") == 0) { StackFrame state = new StackFrame(); state.entity = new EntityInfo(reader["name"], reader["type"], bool.Parse(reader["dynamic"])); stack.Peek().entitySet.Entities.Add(state.entity.EntityName, state.entity); stack.Push(state); } else if (string.CompareOrdinal(reader.LocalName, "entitySet") == 0) { StackFrame state = new StackFrame(); state.entitySet = new EntitySetInfo(reader["name"]); stack.Peek().entity.EntitySets.Add(state.entitySet.Name, state.entitySet); stack.Push(state); } break; case ParserState.Data: BeginRootEntity(reader); break; case ParserState.Entity: if (stack.Peek().entity.Properties.ContainsKey(XmlConvert.DecodeName(reader.LocalName))) { BeginProperty(reader); } else if (stack.Peek().entity.EntitySets.ContainsKey(XmlConvert.DecodeName(reader.LocalName))) { BeginEntitySet(reader); } else { throw new InvalidOperationException("Don't know how to handle element " + reader.LocalName); } break; case ParserState.EntitySet: if (stack.Peek().entitySet.Entities.ContainsKey(reader.LocalName)) { BeginNestedEntity(reader); } else { throw new InvalidOperationException("Don't know how to handle element " + reader.LocalName); } break; case ParserState.ArrayProperty: if (string.CompareOrdinal(reader.LocalName, "item") == 0) { this.state = ParserState.ArrayItem; } else { throw new InvalidOperationException("Expecting <item> but encountered " + reader.LocalName); } break; case ParserState.Errors: if (string.CompareOrdinal(reader.LocalName, "errors") == 0) { state = ParserState.Error; break; } return(default(T)); case ParserState.Error: if (string.CompareOrdinal(reader.LocalName, "error") == 0) { ReadErrorMessages(reader); } break; default: break; } break; case XmlNodeType.EndElement: switch (this.state) { case ParserState.Root: ValidateEndElement(reader.LocalName, "queryResult", ParserState.Errors); break; case ParserState.Errors: if (string.CompareOrdinal(reader.LocalName, "errors") == 0) { ValidateEndElement(reader.LocalName, "errors", ParserState.Root); } return(default(T)); case ParserState.Error: if (string.CompareOrdinal(reader.LocalName, "error") == 0) { break; } ValidateEndElement(reader.LocalName, "errors", ParserState.Root); return(default(T)); case ParserState.Data: ValidateEndElement(reader.LocalName, "data", ParserState.Root); break; case ParserState.Template: ValidateEndElement(reader.LocalName, "template", ParserState.Root); break; case ParserState.EntityTemplate: if ((string.CompareOrdinal(reader.LocalName, "entity") != 0) && (string.CompareOrdinal(reader.LocalName, "entitySet") != 0)) { throw new InvalidOperationException("Expecting </entity> or </entitySet> but encountered " + reader.LocalName); } stack.Pop(); if (stack.Count == 0) { this.state = ParserState.Template; } break; case ParserState.PropertyTemplate: ValidateEndElement(reader.LocalName, "property", ParserState.EntityTemplate); break; case ParserState.Property: EndProperty(reader); break; case ParserState.ArrayProperty: EndArrayProperty(reader); break; case ParserState.ArrayItem: ValidateEndElement(reader.LocalName, "item", ParserState.ArrayProperty); break; case ParserState.Entity: if (string.CompareOrdinal(reader.LocalName, stack.Peek().elementName) != 0) { throw new InvalidOperationException(string.Format("Expecting </{0}> but encountered {1}", stack.Peek().elementName, reader.LocalName)); } if (stack.Count == 1) { return(EndRootEntity()); } else { EndNestedEntity(); } break; case ParserState.EntitySet: EndEntiySet(reader); break; default: throw new InvalidOperationException(string.Format("Not expecting element {0} while in state {1}", reader.LocalName, this.state)); } break; case XmlNodeType.Text: switch (this.state) { case ParserState.Property: ProcessPropertyValue(reader); break; case ParserState.ArrayItem: ProcessArrayPropertyItem(reader); break; } break; } } return(default(T)); }