/// <summary> /// Parses an object from <paramref name="r"/> using <paramref name="a"/> to locate /// a suitable class definition to populate. /// </summary> /// <param name="r">The <see cref="T:System.Xml.XmlReader"/> from which to parse the object</param> /// <param name="a"><paramref name="s"/> in object form</param> /// <returns>A <see cref="MARC.Everest.Formatters.XML.ITS1.Its1FormatterParseResult"/> containing the results of the parse</returns> /// <remarks> /// <para>This method differs from the <seealso cref="F:Parse(System.Xml.XmlReader)"/> method in that it /// will only look within the specified assembly for a suitable class to populate.</para> /// <para> /// This method will not check the current learned type repository for a class to serialize (ie: it will always /// check the assembly regardless of what has been formatted prior) /// </para> /// </remarks> public IFormatterParseResult Parse(XmlReader r, Assembly a) { ThrowIfDisposed(); var resultContext = new XmlIts1FormatterParseResult(ResultCode.Accepted, null); if (!(r is XmlStateReader)) r = new XmlStateReader(r); // Initial state if (r.ReadState == ReadState.Initial) while (r.NodeType != XmlNodeType.Element) r.Read(); // Detect if we can parse this... //if (r.NamespaceURI != "urn:hl7-org:v3") // throw new XmlException(string.Format("Can't parse '{0}' in namespace '{1}'. The data does not appear to be an HL7v3 instance", r.LocalName, r.NamespaceURI), null); // Predicate will find the mapped type for us Predicate<Type> typeComparator = delegate(Type t) { object[] structureAttribute = t.GetCustomAttributes(typeof(StructureAttribute), true); if (structureAttribute.Length > 0 && ((structureAttribute[0] as StructureAttribute).StructureType == StructureAttribute.StructureAttributeType.Interaction || (structureAttribute[0] as StructureAttribute).IsEntryPoint) && (structureAttribute[0] as StructureAttribute).Name == r.LocalName && (structureAttribute[0] as StructureAttribute).NamespaceUri == r.NamespaceURI) return true; return false; }; // Try to find the value if it doesn't succeed, try to build it and try to find it again #if WINDOWS_PHONE Type fType = a.GetTypes().Find(typeComparator); #else Type fType = Array.Find<Type>(a.GetTypes(), typeComparator); #endif // Found the type if (fType != null) resultContext.Structure = this.ParseObject(r, fType, fType, resultContext); else resultContext.AddResultDetail( new ResultDetail(ResultDetailType.Error, String.Format("Could not find a type to de-serialize '{0}' into", r.Name), r.ToString(), null) ); // Set the acceptance code resultContext.Code = CalculateResultCode(resultContext.Details); return resultContext; }
/// <summary> /// Parse an object from <see cref="T:System.Xml.XmlReader"/> <paramref name="r"/> /// </summary> /// <param name="r">The <see cref="T:System.Xml.XmlReader"/> to parse an object from</param> /// <returns>A <see cref="T:MARC.Everest.Formatters.XML.ITS1.Its1FormatterParseResult"/> containing the formatted instance</returns> /// <remarks> /// <para> /// This particular overload of the Graph method can be used to graph objects into a <see cref="T:System.Xml.XmlWriter"/> and can provide /// an opportunity to use Everest as an assistant (or XmlSerializerSurrogate) for more complex systems like WCF. /// </para> /// <example> /// <code lang="cs" title="Using Everest as a Serializer Assistant"> /// <![CDATA[ /// StringWriter sw = new StringWriter("<hello><MCCI_IN000002CA xmlns=\"urn:hl7-org:v3\"/></hello>"); /// XmlReader reader = XmlReader.Create(sw); /// reader.Read(); // Read <hello> /// /// Formatter f = new Formatter(); /// f.GraphAides.Add(typeof(MARC.Everest.Formatters.XML.DataTypes.R1.Formatter)); /// f.ValidateConformance = false; /// var result = f.Parse(reader); /// /// reader.Read(); /// reader.Close(); /// Console.WriteLine(result.Code); /// /// ]]> /// </code> /// </example> /// <para> /// When using this method, it is recommended that you pass a <see cref="T:MARC.Everest.Xml.XmlStateReader"/> as it /// will allow the formatter to give additional location information when reporting issues. /// </para> /// </remarks> public IFormatterParseResult Parse(XmlReader r) { ThrowIfDisposed(); // Clear existing results XmlIts1FormatterParseResult resultContext = new XmlIts1FormatterParseResult(ResultCode.Accepted, null); if (!(r is XmlStateReader)) r = new XmlStateReader(r); // Initial state if (r.ReadState == ReadState.Initial) while (r.NodeType != XmlNodeType.Element) r.Read(); // Detect if we can parse this... //if (r.NamespaceURI != "urn:hl7-org:v3") // throw new XmlException(string.Format("Can't parse '{0}' in namespace '{1}'. The data does not appear to be an HL7v3 instance", r.LocalName, r.NamespaceURI), null); // Do we have a formatter for the object Type mappedType; // Predicate will find the mapped type for us Predicate<Type> typeComparator = delegate(Type t) { object[] structureAttribute = t.GetCustomAttributes(typeof(StructureAttribute), true); if (structureAttribute.Length > 0 && ((structureAttribute[0] as StructureAttribute).StructureType == StructureAttribute.StructureAttributeType.Interaction || (structureAttribute[0] as StructureAttribute).IsEntryPoint) && (structureAttribute[0] as StructureAttribute).Name == r.LocalName && (structureAttribute[0] as StructureAttribute).NamespaceUri == r.NamespaceURI) return true; return false; }; // Try to find the value if it doesn't succeed, try to build it and try to find it again for (int i = 0; i < 2 && resultContext.Structure == null; i++) { if (s_rootNameMaps.TryGetValue(r.LocalName, out mappedType)) // Try to get a root name map { resultContext.Structure = ParseObject(r, mappedType, mappedType, resultContext); resultContext.Code = CalculateResultCode(resultContext.Details); return resultContext; } else if (i == 0) // Try to build the cache for this root name { // Last attempt, try to find a type in the app domain that we can scan! Predicate<Assembly> asmPredicate = delegate(Assembly a) { try { #if WINDOWS_PHONE return a.GetTypes().Exists(typeComparator); #else return Array.Find<Type>(a.GetTypes(), typeComparator) != null; #endif } catch { return false; } }; #if WINDOWS_PHONE Assembly asm = AppDomain.CurrentDomain.GetAssemblies().Find(asmPredicate); #else Assembly asm = Array.Find<Assembly>(AppDomain.CurrentDomain.GetAssemblies(), asmPredicate); #endif if (asm == null) // Couldn't find assembly... ditch break; else return Parse(r, asm); //BuildCache(new Type[] { Array.Find<Type>(asm.GetTypes(), typeComparator) }); } //i++; } resultContext.AddResultDetail(new ResultDetail(ResultDetailType.Error, String.Format("Could not find a type to de-serialize '{0}' into", r.Name), r.ToString(), null)); resultContext.Code = ResultCode.Rejected; return resultContext; }
/// <summary> /// Parse an object from <see cref="T:System.Xml.XmlReader"/> <paramref name="r"/> using the type /// hint <param name="t"/> /// </summary> /// <param name="r">The <see cref="T:System.Xml.XmlReader"/> to parse an object from</param> /// <param name="t">The type hint to parse the object</param> /// <returns>A <see cref="T:MARC.Everest.Formatters.XML.ITS1.Its1FormatterParseResult"/> containing the formatted instance</returns> /// <remarks> /// <para> /// This particular overload of the Graph method can be used to graph objects into a <see cref="T:System.Xml.XmlWriter"/> and can provide /// an opportunity to use Everest as an assistant (or XmlSerializerSurrogate) for more complex systems like WCF. /// </para> /// <example> /// <code lang="cs" title="Using Everest as a Serializer Assistant"> /// <![CDATA[ /// StringWriter sw = new StringWriter("<hello><MCCI_IN000002CA xmlns=\"urn:hl7-org:v3\"/></hello>"); /// XmlReader reader = XmlReader.Create(sw); /// reader.Read(); // Read <hello> /// /// Formatter f = new Formatter(); /// f.GraphAides.Add(typeof(MARC.Everest.Formatters.XML.DataTypes.R1.Formatter)); /// f.ValidateConformance = false; /// var result = f.Parse(reader, typeof(MCCI_IN000002CA)); /// /// reader.Read(); /// reader.Close(); /// Console.WriteLine(result.Code); /// /// ]]> /// </code> /// </example> /// <para> /// When using this method, it is recommended that you pass a <see cref="T:MARC.Everest.Xml.XmlStateReader"/> as it /// will allow the formatter to give additional location information when reporting issues. /// </para> /// </remarks> public IFormatterParseResult Parse(XmlReader r, Type t) { if (!(r is XmlStateReader)) r = new XmlStateReader(r); // Initial state if (r.ReadState == ReadState.Initial) while (r.NodeType != XmlNodeType.Element) r.Read(); // Detect if we can parse this... if (r.NamespaceURI != "urn:hl7-org:v3") throw new XmlException(string.Format("Can't parse '{0}' in namespace '{1}'. The data does not appear to be an HL7v3 instance", r.LocalName, r.NamespaceURI), null); var resultContext = new XmlIts1FormatterParseResult(ResultCode.Accepted, null); resultContext.Structure = ParseObject(r, t, null, resultContext); return resultContext; }
public virtual IGraphable ParseObject(XmlReader r, Type useType, Type interactionContext, XmlIts1FormatterParseResult resultContext) { ThrowIfDisposed(); // Find a helper string typeName = GetStructureName(useType); IXmlStructureFormatter ixsf = null; // xsi type? - We want to adjust the type based on this value try { string xsiType = r.GetAttribute("type", NS_XSI); // Is this model / type registered somewhere ? if ((this.Settings & SettingsType.AlwaysCheckForOverrides) != 0 && xsiType == null && !typeof(ANY).IsAssignableFrom(useType)) xsiType = this.CreateXSITypeName(useType, interactionContext, r as IXmlNamespaceResolver); if (xsiType != null) { if (useType.IsInterface || typeof(ANY).IsAssignableFrom(useType)) // HACK: We don't override the use type for ANY derivatives as some types are special and require special typing ixsf = this.GetAdjustedFormatter(xsiType); //Util.ParseXSITypeName(r.GetAttribute("type", NS_XSI)); else useType = this.ParseXSITypeName(xsiType, r as IXmlNamespaceResolver); } else ixsf = (IXmlStructureFormatter)this.GraphAides.Find(t => t.HandleStructure.Contains(typeName)); } catch (Exception e) { resultContext.AddResultDetail(new ResultDetail(ResultDetailType.Error, e.Message, r.ToString(), e)); } string currentPath = r is XmlStateReader ? (r as XmlStateReader).CurrentPath : r.Name; // Does a helper have it? if (ixsf != null) { ixsf.Host = this; var aideResult = ixsf.Parse(r, useType); resultContext.AddResultDetail(aideResult.Details); return aideResult.Structure; } #if WINDOWS_PHONE ITypeFormatter formatter = m_codeGeneratorFormatter.GetFormatter(useType); if (formatter == null) formatter = new ReflectFormatter(); #else ITypeFormatter formatter = m_codeGeneratorFormatter.GetFormatter(useType); // Is there a formatter and if there is not a formatter // can we create one? if (formatter == null && (Settings & SettingsType.UseGeneratorFormat) == SettingsType.UseGeneratorFormat) s_threadPool.QueueUserWorkItem((WaitCallback)delegate(object state) { BuildCache(new Type[] { (Type)state }); }, useType); // If there is no connector can we use reflection? if (formatter == null && (Settings & SettingsType.UseReflectionFormat) == SettingsType.UseReflectionFormat) formatter = new ReflectFormatter(); else if (formatter == null && (Settings & SettingsType.UseGeneratorFormat) == SettingsType.UseGeneratorFormat) { s_threadPool.WaitOne(); formatter = m_codeGeneratorFormatter.GetFormatter(useType); } #endif if (formatter == null) throw new InvalidOperationException(string.Format("Couldn't format '{0}' at {1}, verify formatter settings", useType.FullName, r.ToString())); // Parse using the formatter formatter.Host = this; // Parse the object IGraphable result = (IGraphable)formatter.Parse(r, useType, interactionContext, resultContext); IResultDetail[] details = null; if (details != null && result == null || ValidateConformance && (!formatter.Validate(result, currentPath, out details))) resultContext.AddResultDetail(details.Length > 0 ? details : new IResultDetail[] { new ResultDetail(ValidateConformance ? ResultDetailType.Error : ResultDetailType.Warning, String.Format("Couldn't parse type '{0}'", useType.ToString()), currentPath) }); return result; }