void _ExportDerivedTypes(ExportedType exportedType) { if (exportedType == null) return; if (exportedType.DerivedTypesExported) return; XmlNode typeNode = exportedType.Element; if (typeNode == null) return; if (exportedType.TypeInfo == null) return; Type t = exportedType.TypeInfo.Type; if (t == null) return; if (t == typeof(System.Object)) // don't export all subclasses of System.Object. likely to result in a large list full of irrelevant stuff (ha ha) return; List<Type> subclasses = new List<Type>(); TypeUtil.FindSubclasses(t, subclasses); if (subclasses.Count == 0) return; // mark that we are exporting the derived types for this type, so that if we re-enter, we don't get multiple DerivedType nodes exportedType.DerivedTypesExported = true; // write out derived types (subclasses and interface implementors) XmlElement el = _doc.CreateElement("DerivedTypes"); List<string> derivedTypeNames = new List<string>(); foreach (Type subClassType in subclasses) { if (!TypeUtil.IsInstantiable(subClassType)) // skip non-instantiable types, since we can't deserialize them continue; string subTypeName = TypeUtil.GetTypeFullName(subClassType); // export the derived type if (_Export(subClassType, false, false)) derivedTypeNames.Add(subTypeName); } derivedTypeNames.Sort(); // append derived types only if it has something in it if (derivedTypeNames.Count > 0) { foreach (string name in derivedTypeNames) { XmlElement subTypeEl = _doc.CreateElement("Type"); subTypeEl.InnerText = name; el.AppendChild(subTypeEl); } typeNode.AppendChild(el); } }
/// <summary> /// Builds and exports the xml schema. /// </summary> /// <param name="outputFileName">The filename to write the schema to.</param> public void Process(string outputFileName) { #if DEBUG Profiler.Instance.StartBlock("TorqueXmlSchemaExporter.Process"); #endif List<Assembly> assemblies = new List<Assembly>(); TypeUtil.PopulateAssemblyList(assemblies); _doc = new XmlDocument(); _root = _doc.CreateElement("TorqueSchema"); _doc.AppendChild(_root); _explicitTypesNode = _doc.CreateElement("ExplicitTypes"); _root.AppendChild(_explicitTypesNode); _referencedTypesNode = _doc.CreateElement("ReferencedTypes"); _root.AppendChild(_referencedTypesNode); foreach (Assembly a in assemblies) { Type[] types = a.GetTypes(); foreach (Type t in types) { // skip anthing that isn't an instantiable reference type if (!t.IsClass || t.IsInterface || t.IsAbstract) continue; // skip it unless it has a TorqueXmlSchemaType attribute object[] attrs = t.GetCustomAttributes(false); bool hasSchemaAttr = false; foreach (object attr in attrs) { if (attr is TorqueXmlSchemaType) { hasSchemaAttr = true; break; } } if (!hasSchemaAttr) continue; // export it _Export(t, true, false); } } ExportedType[] exportedTypes = new ExportedType[_processedTypes.Values.Count]; _processedTypes.Values.CopyTo(exportedTypes, 0); // sort the types so that the CRC of the schema won't change unless new types are added Array.Sort(exportedTypes); // add nodes to the appropriate root - explicit or referenced foreach (ExportedType typeInfo in exportedTypes) { if (typeInfo.Element != null) { if (typeInfo.Explicit) _explicitTypesNode.AppendChild(typeInfo.Element); else _referencedTypesNode.AppendChild(typeInfo.Element); } } // save document _doc.Save(outputFileName); #if DEBUG Profiler.Instance.EndBlock("TorqueXmlSchemaExporter.Process"); #endif }
bool _Export(Type t, bool explicitlyExported, bool exportSubclasses) { try { ExportedType exportInfo; if (_processedTypes.TryGetValue(t, out exportInfo)) { // can't make a type un-explicit after it has been explicitized if (explicitlyExported && !exportInfo.Explicit) exportInfo.Explicit = explicitlyExported; if (exportSubclasses) { // if the type was already exported, make sure it has the derived type information if (exportInfo.Element != null) _ExportDerivedTypes(exportInfo); } return exportInfo.Element != null; } // create the new exported type and mark it as exported exportInfo = new ExportedType(); if (_processedTypes.ContainsKey(t)) _processedTypes.Remove(t); _processedTypes.Add(t, exportInfo); exportInfo.Explicit = explicitlyExported; // see if this type has a TorqueXmlSchemaType attribute, not inheriting it from parents object[] tCAttrs = t.GetCustomAttributes(typeof(TorqueXmlSchemaType), false); TorqueXmlSchemaType xmlTypeAttr = null; if (tCAttrs.Length > 0) xmlTypeAttr = tCAttrs[0] as TorqueXmlSchemaType; string typeName = t.Name; if (xmlTypeAttr != null) { // is exporting disabled? if (!xmlTypeAttr.ExportType) return false; // remap type name? if (!string.IsNullOrEmpty(xmlTypeAttr.Name)) typeName = xmlTypeAttr.Name; } // check for hidden fields Dictionary<string, bool> fieldExport = new Dictionary<string, bool>(); // we include field declarations from the parent classes, so that hidden fields do not need to be rehidden in each subclass object[] fieldAttrs = t.GetCustomAttributes(typeof(TorqueXmlSchemaField), true); // iterate back to front so that the most derived attribute for a given field name is used Array.Reverse(fieldAttrs); foreach (TorqueXmlSchemaField txsf in fieldAttrs) { if (string.IsNullOrEmpty(txsf.Name)) throw new Exception("Name required for TorqueXmlSchemaField, type: " + t.FullName); if (!fieldExport.ContainsKey(txsf.Name)) fieldExport[txsf.Name] = false; fieldExport[txsf.Name] = txsf.ExportField; } XmlElement el = null; TypeInfo ti = TypeUtil.FindTypeInfo(t.FullName); Assert.Fatal(ti != null, "Can't load type " + t.FullName); exportInfo.TypeInfo = ti; List<IFieldOrProperty> fieldsAndProperties = ti.FieldsAndProperties; XmlElement typeNode = _doc.CreateElement("Type"); exportInfo.Element = typeNode; XmlAttribute attr = _doc.CreateAttribute("name"); attr.Value = typeName; typeNode.Attributes.Append(attr); attr = _doc.CreateAttribute("fullName"); attr.Value = TypeUtil.GetTypeFullName(t); typeNode.Attributes.Append(attr); // write out any dependencies el = _doc.CreateElement("Dependencies"); tCAttrs = t.GetCustomAttributes(true); List<String> depTypes = new List<string>(); foreach (object tcAttr in tCAttrs) { if (tcAttr is TorqueXmlSchemaDependency) { TorqueXmlSchemaDependency depAttr = tcAttr as TorqueXmlSchemaDependency; if (depAttr.Type != null) { depTypes.Add(TypeUtil.GetTypeFullName(depAttr.Type)); } } } depTypes.Sort(); foreach (string depTypeName in depTypes) { XmlElement depType = _doc.CreateElement("Type"); depType.InnerText = depTypeName; el.AppendChild(depType); } // append dependency list only if it has something in it if (el.ChildNodes.Count > 0) typeNode.AppendChild(el); if (exportSubclasses) _ExportDerivedTypes(exportInfo); // write out component flag if (ti.Type.IsSubclassOf(typeof(TorqueComponent))) { el = _doc.CreateElement("IsComponent"); el.InnerText = TorqueXmlSchemaDefaults.BoolTrue; typeNode.AppendChild(el); } // write out delegate flag if its a delegate bool isDelegate = ti.Type.IsSubclassOf(typeof(System.Delegate)); if (isDelegate) { el = _doc.CreateElement("IsDelegate"); el.InnerText = isDelegate ? TorqueXmlSchemaDefaults.BoolTrue : TorqueXmlSchemaDefaults.BoolFalse; typeNode.AppendChild(el); } // write out enum flag if (ti.Type.IsEnum) { el = _doc.CreateElement("IsEnum"); el.InnerText = ti.Type.IsEnum ? TorqueXmlSchemaDefaults.BoolTrue : TorqueXmlSchemaDefaults.BoolFalse; typeNode.AppendChild(el); } // write out instantiable flag, but only if it is not instantiable bool isInstantiable = !isDelegate && TypeUtil.IsInstantiable(ti.Type); if (!isInstantiable) { el = _doc.CreateElement("IsInstantiable"); el.InnerText = isInstantiable ? TorqueXmlSchemaDefaults.BoolTrue : TorqueXmlSchemaDefaults.BoolFalse; typeNode.AppendChild(el); } // write out deserializable elements (fields and properties) foreach (IFieldOrProperty fieldOrProperty in fieldsAndProperties) { // skip it? bool export = true; if (fieldExport.TryGetValue(fieldOrProperty.XmlName, out export)) if (!export) continue; XmlElement elemNode = _doc.CreateElement("Element"); typeNode.AppendChild(elemNode); // write static flag if (fieldOrProperty.IsStatic) { el = _doc.CreateElement("IsStatic"); el.InnerText = TorqueXmlSchemaDefaults.BoolTrue; elemNode.AppendChild(el); } // retrieve XML schema attribute, if any TorqueXmlSchemaType xmlAttr = null; object[] cAttrs = fieldOrProperty.GetCustomAttributes(true); foreach (object cAttr in cAttrs) { if (cAttr is TorqueXmlSchemaType) { xmlAttr = cAttr as TorqueXmlSchemaType; break; } } attr = _doc.CreateAttribute("name"); attr.Value = fieldOrProperty.XmlName; elemNode.Attributes.Append(attr); // is this thingy a list? TypeInfo fieldTI = TypeUtil.FindTypeInfo(fieldOrProperty.DeclaredType.FullName); Assert.Fatal(fieldTI != null, "Can't find type for element: " + fieldOrProperty.DeclaredType.FullName); XmlElement child = null; if (fieldTI != null && fieldTI.IsList) { bool exportedAListType = false; el = _doc.CreateElement("IsList"); el.InnerText = TorqueXmlSchemaDefaults.BoolTrue; elemNode.AppendChild(el); // append Type elements for all of the possible types of the list Type listType = DeserializerUtil.GetListType(fieldTI.Type); // if it is a list, don't export it TypeInfo listTI = TypeUtil.FindTypeInfo(listType.FullName); if (listTI != null && !listTI.IsList) { exportedAListType = true; el = _doc.CreateElement("Type"); el.InnerText = TypeUtil.GetTypeFullName(listType); if (_Export(listType, false, true)) elemNode.AppendChild(el); } Assert.Fatal(exportedAListType, String.Format("Error, did not export any list element types for field {0} in type {1}", fieldOrProperty.XmlName, ti.Type.FullName)); } else { child = _doc.CreateElement("Type"); child.InnerText = TypeUtil.GetTypeFullName(fieldOrProperty.DeclaredType); elemNode.AppendChild(child); } if (xmlAttr != null) { if (xmlAttr.DefaultValue != null) { child = _doc.CreateElement("DefaultValue"); child.InnerText = xmlAttr.DefaultValue; elemNode.AppendChild(child); } if (xmlAttr.IsDefaultValueOf) { child = _doc.CreateElement("DefaultIsValueOf"); child.InnerText = TorqueXmlSchemaDefaults.BoolTrue; elemNode.AppendChild(child); } } // don't export list types since we already handled them if (fieldTI == null || !fieldTI.IsList) _Export(fieldOrProperty.DeclaredType, false, false); } return exportInfo.Element != null; } catch (Exception) { return false; } }