private static void SerializeElement(XmlWriter writer, Element element) { // Write start tag XmlComponent component = KmlFactory.FindType(element.GetType()); // Custom elements take priority over component ICustomElement customElement = element as ICustomElement; if (customElement != null) { customElement.CreateStartElement(writer); if (!customElement.ProcessChildren) { return; // Don't need to to any more work. } } else if (component != null) { writer.WriteStartElement(component.Name, component.NamespaceUri); } else { // We can't handle it so ignore it System.Diagnostics.Debug.WriteLine("Unknown Element type - please register first." + element.GetType()); return; // Skip } // Write the attributes - unknown, serialized then namespaces. foreach (var att in element.Attributes) { writer.WriteAttributeString(att.Prefix, att.Name, att.NamespaceUri, att.Value); } WriteAttributes(writer, element); foreach (var ns in element.Namespaces.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml)) { writer.WriteAttributeString("xmlns", ns.Key, string.Empty, ns.Value); } // Now the text part WriteData(writer, element.InnerText); // Now write the elements - serialized, children then unknown children. WriteElements(writer, element); SerializeElements(writer, element.OrderedChildren); SerializeElements(writer, element.Orphans); // Finished... writer.WriteEndElement(); }
// Because the Element's won't be nested too deep (max 100), a Stack based // iterative approach is not necessary so recursion is used for clarity. private static IEnumerable <Element> WalkElement(Element element) { ICustomElement customElement = element as ICustomElement; if ((customElement == null) || customElement.ProcessChildren) { yield return(element); // Is a valid Element // Explore the children foreach (var child in element.Children) { foreach (var e in WalkElement(child)) { yield return(e); } } // Explore the properties TypeBrowser browser = TypeBrowser.Create(element.GetType()); foreach (var property in browser.Elements) { // All properties with their ElementName set to null will be Elements // Check here to avoid the GetValue the property is not an Element. if (property.Item2.ElementName == null) { object value = property.Item1.GetValue(element, null); if (value != null) { foreach (var e in WalkElement((Element)value)) { yield return(e); } } } } } }
/// <summary> /// Using the Verify property, invokes the verification handler. /// </summary> /// <param name="element"></param> static private bool _Verify(object element) { // Cast element to ICustomElement. ICustomElement customElement = (ICustomElement)element; // Get class and method name of verifier routine. string assemblyName = String.Empty; string className = String.Empty; string methodName = String.Empty; string verifier = customElement.Verifier; Assembly assembly = null; int period = verifier.IndexOf("#"); if (period <= 0) { throw new Exception("Verifier property is not in the correct format: <AssemblyName>#<TypeName>.<MethodName>."); } assemblyName = customElement.Verifier.Substring(0, period); assemblyName = Path.GetFileNameWithoutExtension(assemblyName); //Using LoadWithPartialName rather than LoadFrom, in order to avoid the same Assembly from being loaded twice. #pragma warning disable 618 assembly = Assembly.LoadWithPartialName(assemblyName); #pragma warning restore 618 verifier = verifier.Substring(period + 1, verifier.Length - period - 1); period = verifier.LastIndexOf("."); if (period <= 0) { throw new Exception("Verifier property is not in the correct format: <AssemblyName>#<TypeName>.<MethodName>."); } className = verifier.Substring(0, period); methodName = verifier.Substring(period + 1, verifier.Length - period - 1); Type originalType = assembly.GetType(className, true, false); MethodInfo methodInfo = originalType.GetMethod(methodName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); if (methodInfo == null) { throw new Exception("Could not find method '" + methodName + "' on type '" + className + ". Method must be public and declared directly on the class, i.e. not inherited."); } // // Use reflection to call the verification routine specified in this.Verifier. // For better readability, only print this info once for multiple-verification scenarios // if (_verifierFirstCalled) { _verifierFirstCalled = false; GlobalLog.LogStatus("Calling verification routine: " + assemblyName + "#" + className + "." + methodName + "..."); } object[] paramarray = new object[] { customElement }; object returnval = null; if (methodInfo.IsStatic) { returnval = methodInfo.Invoke(null, paramarray); } else { object obj = Activator.CreateInstance( originalType, BindingFlags.Public | BindingFlags.Instance, null, new object[0], null ); returnval = methodInfo.Invoke(obj, paramarray); } // If the return value was void, return true to specify // that all verification is done. Otherwise, convert the return value // to bool and return that. A 'false' value specifies that there is // more verification to do; the verifier should be called again. // This allows interactive tests for animations, etc. if (returnval == null) { return(true); } else { return(Convert.ToBoolean(returnval)); } }