// Called every time the attached XML file is saved within visual studio. protected override byte[] GenerateCode(string inputFileName, string inputFileContent) { // class name should always the same as output file name string className = Path.GetFileNameWithoutExtension(inputFileName); SchemaLoader typeLoader = new SchemaLoader(); typeLoader.Load(inputFileName); string[] fakeArgs = {"CustomToolDomGen", inputFileName, Path.GetFileNameWithoutExtension(inputFileName) + ".cs", className, FileNameSpace}; return System.Text.Encoding.ASCII.GetBytes(SchemaGen.Generate(typeLoader, "", FileNameSpace, className, fakeArgs)); }
// Called every time the attached XML file is saved within visual studio. protected override byte[] GenerateCode(string inputFileName, string inputFileContent) { // class name should always the same as output file name string className = Path.GetFileNameWithoutExtension(inputFileName); SchemaLoader typeLoader = new SchemaLoader(); typeLoader.Load(inputFileName); string[] fakeArgs = { "CustomToolDomGen", inputFileName, Path.GetFileNameWithoutExtension(inputFileName) + ".cs", className, FileNameSpace }; return(System.Text.Encoding.ASCII.GetBytes(SchemaGen.Generate(typeLoader, "", FileNameSpace, className, fakeArgs))); }
private static void GenerateEnums(StringBuilder sb, SchemaLoader typeLoader, XmlQualifiedName[] namespaces, Dictionary <string, string> domNodeTypeToClassName, Dictionary <string, string> classNameToDomNodeType) { // Temp code // Currently the only way I can see to find out which strings are enum type // is to search for the StringEnumRule on the AttributeType // If this exists then use reflection to access the values list // This could and should be done in some nicer way in the future! System.Reflection.FieldInfo fInfo = typeof(StringEnumRule).GetField("m_values", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (fInfo != null) { var enumAttributeTypes = new HashSet <AttributeType>(); foreach (AttributeType attributeType in typeLoader.GetAttributeTypes()) { StringEnumRule rule = attributeType.Rules.FirstOrDefault(x => x is StringEnumRule) as StringEnumRule; if (rule != null) { if (enumAttributeTypes.Add(attributeType)) { string[] values = fInfo.GetValue(rule) as string[]; if (values != null) { string enumTypeName = GetClassName(namespaces, attributeType, domNodeTypeToClassName, classNameToDomNodeType); WriteLine(sb, ""); WriteLine(sb, " public enum {0}", enumTypeName); WriteLine(sb, " {{"); foreach (string value in values) { WriteLine(sb, " " + value + ","); } if (values.Length > 0) { sb.Length = sb.Length - 1; } WriteLine(sb, " }}"); } } } } } }
public void TestGenerate() { //"usage: DomGen {schemaPath} {outputPath} {schemaNamespace} {classNamespace} -a(dapters)" //"eg: DomGen echo.xsd Schema.cs http://sce/audio Sce.Audio -a" string inputPath = ".\\Resources\\test_customized.xsd"; string schemaNamespace = "test"; string codeNamespace = "testCodeNamespace"; string className = "TestClass"; SchemaLoader typeLoader = new SchemaLoader(); typeLoader.Load(inputPath); // Normal test string schemaClass = SchemaGen.Generate(typeLoader, schemaNamespace, codeNamespace, className, EmptyArray<string>.Instance); Validate(schemaClass, schemaNamespace, codeNamespace, className, false); // Test with -annotatedOnly option string[] args = new string[] { inputPath, "", schemaNamespace, codeNamespace, "-annotatedOnly" }; schemaClass = SchemaGen.Generate(typeLoader, schemaNamespace, codeNamespace, className, args); Validate(schemaClass, schemaNamespace, codeNamespace, className, true); }
/// <summary> /// Generates the Schema CSharp class</summary> /// <param name="typeLoader">Type loader with loaded type and annotation information</param> /// <param name="schemaNamespace">Target namespace of the schema</param> /// <param name="codeNamespace">Namespace of the class ot be generated</param> /// <param name="className">Name of the class to be generated</param> /// <param name="args">Commandline arguments</param> /// <returns>CSharp Schema class as string</returns> public static string Generate(SchemaLoader typeLoader, string schemaNamespace, string codeNamespace, string className, string[] args) { bool generateAdapters = false; bool annotatedOnly = false; bool generateEnums = false; for (int i = 4; i < args.Length; i++) { string arg = args[i]; if (arg == "-a" || arg == "-adapters") generateAdapters = true; else if (arg == "-annotatedOnly") annotatedOnly = true; else if (arg == "-enums") generateEnums = true; } XmlSchemaTypeCollection typeCollection = GetTypeCollection(typeLoader, schemaNamespace); string targetNamespace = typeCollection.TargetNamespace; XmlQualifiedName[] namespaces = typeCollection.Namespaces; List<DomNodeType> nodeTypes = new List<DomNodeType>(typeCollection.GetNodeTypes()); // Append additional DomNodeTypes from other namespaces, for example if the xs:import was used. // Don't include the built-in "anyType". // The reason to append is that if there is a conflict with the imported types, priority should // be given to the types defined in the importing schema file. foreach (XmlQualifiedName knownNamespace in namespaces) { if (knownNamespace.Namespace != targetNamespace && knownNamespace.Namespace != "http://www.w3.org/2001/XMLSchema") nodeTypes.AddRange(typeCollection.GetNodeTypes(knownNamespace.Namespace)); } List<ChildInfo> rootElements = new List<ChildInfo>(typeCollection.GetRootElements()); StringBuilder sb = new StringBuilder(); GenerateFileProlog(codeNamespace, args, sb); WriteLine(sb, " public static class {0}", className); WriteLine(sb, " {{"); WriteLine(sb, " public const string NS = \"{0}\";", targetNamespace); WriteLine(sb, ""); WriteLine(sb, " public static void Initialize(XmlSchemaTypeCollection typeCollection)"); WriteLine(sb, " {{"); WriteLine(sb, " Initialize((ns,name)=>typeCollection.GetNodeType(ns,name),"); WriteLine(sb, " (ns,name)=>typeCollection.GetRootElement(ns,name));"); WriteLine(sb, " }}"); WriteLine(sb, ""); WriteLine(sb, " public static void Initialize(IDictionary<string, XmlSchemaTypeCollection> typeCollections)"); WriteLine(sb, " {{"); WriteLine(sb, " Initialize((ns,name)=>typeCollections[ns].GetNodeType(name),"); WriteLine(sb, " (ns,name)=>typeCollections[ns].GetRootElement(name));"); WriteLine(sb, " }}"); WriteLine(sb, ""); WriteLine(sb, " private static void Initialize(Func<string, string, DomNodeType> getNodeType, Func<string, string, ChildInfo> getRootElement)"); WriteLine(sb, " {{"); StringBuilder fieldSb = new StringBuilder(); Dictionary<string, string> domNodeTypeToClassName = new Dictionary<string, string>(nodeTypes.Count); Dictionary<string, string> classNameToDomNodeType = new Dictionary<string, string>(nodeTypes.Count); foreach (DomNodeType nodeType in nodeTypes) { // Determine if the type should be included or skipped // If the -annotatedOnly argument is set: types will be included // ONLY IF <sce.domgen include="true"> is defined for this type, all other types will be skipped // If -annotatedOnly is NOT set: types will be included by default // UNLESS <sce.domgen include="false" is explicitly set for this type bool include = !annotatedOnly; XmlNode annotation; if (typeLoader.DomGenAnnotations.TryGetValue(nodeType.Name, out annotation)) { foreach (XmlAttribute attribute in annotation.Attributes) { if (attribute.Name == "include") include = Boolean.Parse(attribute.Value); // will throw if value is not a valid boolean } } if (!include) continue; // skip this type if it's not to be included string ns = codeNamespace; if (ns == null) ns = targetNamespace; string typeName = GetClassName(namespaces, nodeType, domNodeTypeToClassName, classNameToDomNodeType); GenerateInitializers(nodeType, typeName, sb); WriteLine(sb, ""); WriteLine(fieldSb, ""); GenerateFields(nodeType, typeName, fieldSb); } if (generateEnums) { GenerateEnums(fieldSb, typeLoader, namespaces, domNodeTypeToClassName, classNameToDomNodeType); } foreach (ChildInfo rootElement in rootElements) { string fieldName = rootElement.Name + "RootElement"; WriteLine(fieldSb, ""); WriteLine(fieldSb, " public static ChildInfo {0};", fieldName); WriteLine(sb, " {0} = getRootElement(NS, \"{1}\");", fieldName, rootElement.Name); } WriteLine(sb, " }}"); sb.Append(fieldSb.ToString()); WriteLine(sb, " }}"); if (generateAdapters) { WriteLine(sb, ""); foreach (DomNodeType nodeType in nodeTypes) { string modifiers = (nodeType.IsAbstract) ? "abstract " : ""; string adapterClassName = GetClassName(nodeType, domNodeTypeToClassName); string adapterBaseClassName = "DomNodeAdapter"; if (nodeType.BaseType != DomNodeType.BaseOfAllTypes) adapterBaseClassName = GetClassName(nodeType.BaseType, domNodeTypeToClassName); WriteLine(sb, " public {0}partial class {1} : {2}", modifiers, adapterClassName, adapterBaseClassName); WriteLine(sb, " {{"); foreach (AttributeInfo attrInfo in nodeType.Attributes) { if (attrInfo.DefiningType != nodeType) continue; string typeName = attrInfo.Type.Type.ToString(); typeName = s_attributeTypes[typeName]; string attrName = attrInfo.Name; string propertyName = attrName; if (s_cSharpKeywords.Contains(propertyName)) propertyName = "@" + propertyName; WriteLine(sb, " public {0} {1}", typeName, propertyName); WriteLine(sb, " {{"); string attrInfoName = className + "." + adapterClassName + "." + attrName + "Attribute"; WriteLine(sb, " get {{ return GetAttribute<{0}>({1}); }}", typeName, attrInfoName); WriteLine(sb, " set {{ SetAttribute({0}, value); }}", attrInfoName); WriteLine(sb, " }}"); } foreach (ChildInfo childInfo in nodeType.Children) { if (childInfo.DefiningType != nodeType) continue; string childName = childInfo.Name; string propertyName = childName; string typeName = GetClassName(childInfo.Type, domNodeTypeToClassName); string childInfoName = className + "." + adapterClassName + "." + childName + "Child"; if (childInfo.IsList) { WriteLine(sb, " public IList<{0}> {1}", typeName, propertyName); WriteLine(sb, " {{"); WriteLine(sb, " get {{ return GetChildList<{0}>({1}); }}", typeName, childInfoName); WriteLine(sb, " }}"); } else { WriteLine(sb, " public {0} {1}", typeName, propertyName); WriteLine(sb, " {{"); WriteLine(sb, " get {{ return GetChild<{0}>({1}); }}", typeName, childInfoName); WriteLine(sb, " set {{ SetChild({0}, value); }}", childInfoName); WriteLine(sb, " }}"); } } WriteLine(sb, " }}"); WriteLine(sb, ""); } } GenerateFileEpilog(sb); return sb.ToString(); }
private static void GenerateEnums(StringBuilder sb, SchemaLoader typeLoader, XmlQualifiedName[] namespaces, Dictionary<string, string> domNodeTypeToClassName, Dictionary<string, string> classNameToDomNodeType) { // Temp code // Currently the only way I can see to find out which strings are enum type // is to search for the StringEnumRule on the AttributeType // If this exists then use reflection to access the values list // This could and should be done in some nicer way in the future! System.Reflection.FieldInfo fInfo = typeof(StringEnumRule).GetField("m_values", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (fInfo != null) { var enumAttributeTypes = new HashSet<AttributeType>(); foreach (AttributeType attributeType in typeLoader.GetAttributeTypes()) { StringEnumRule rule = attributeType.Rules.FirstOrDefault(x => x is StringEnumRule) as StringEnumRule; if (rule != null) { if (enumAttributeTypes.Add(attributeType)) { string[] values = fInfo.GetValue(rule) as string[]; if (values != null) { string enumTypeName = GetClassName(namespaces, attributeType, domNodeTypeToClassName, classNameToDomNodeType); WriteLine(sb, ""); WriteLine(sb, " public enum {0}", enumTypeName); WriteLine(sb, " {{"); foreach (string value in values) { WriteLine(sb, " " + value + ","); } if (values.Length > 0) sb.Length = sb.Length - 1; WriteLine(sb, " }}"); } } } } } }
static void Main(string[] args) { string inputPath; string outputPath; string schemaNamespace; string codeNamespace; string className; bool useCacheFile = false; bool upToDate = false; if (args.Length < 4) { Console.WriteLine( "usage:\n" + "DomGen {schemaPath} {outputPath} {schemaNamespace} {classNamespace} {options}\n" + "eg: DomGen echo.xsd Schema.cs http://sce/audio Sce.Audio -a\n" + "options:\n" + "-a or -adapters\n" + " Will generate DomNodeAdapters with properties\n" + "-annotatedOnly\n" + " If the -annotatedOnly argument is set: types will be included ONLY if\n" + " <sce.domgen include=\"true\"> is defined for this type, all other types will\n" + " be skipped.\n" + " If -annotatedOnly is NOT set: types will be included by default UNLESS\n" + " <sce.domgen include=\"false\"> is explicitly set for this type" + "-enums\n" + " Will generate Enum types for all AttributeTypes which have string value restrictions\n" + "-cache\n" + " If -cache is set will generate an intermediate file and will not rebuild the output unless\n" + " the schema has changed\n"); return; } inputPath = args[0]; outputPath = args[1]; schemaNamespace = args[2]; codeNamespace = args[3]; // class name should always be the same as output file name className = Path.GetFileNameWithoutExtension(outputPath); for (int i = 4; i < args.Length; i++) { string arg = args[i]; if (arg == "-cache") { useCacheFile = true; } } var typeLoader = new SchemaLoader(); XmlSchema schema = null; string cacheFile = outputPath + @".dep"; // Temp: Test to see if not rebuilding speeds up our builds... if (useCacheFile && File.Exists(cacheFile)) { // Use special resolver var resolver = new HashingXmlUrlResolver(); typeLoader.SchemaResolver = resolver; schema = typeLoader.Load(inputPath); if (schema != null) { try { string previousHashString = null; using (TextReader reader = File.OpenText(cacheFile)) { previousHashString = reader.ReadLine(); } // Generate hash by concat of hash of each file stream loaded var sb = new StringBuilder(); foreach (byte[] hash in resolver.Hashes) { sb.Append(Convert.ToBase64String(hash)); } string hashString = sb.ToString(); upToDate = (previousHashString == hashString); if (upToDate == false) { using (TextWriter writer = new StreamWriter(cacheFile)) { writer.WriteLine(hashString); } } } catch (Exception) { } } } else { schema = typeLoader.Load(inputPath); } if (upToDate == false) { UTF8Encoding encoding = new UTF8Encoding(); using (FileStream strm = File.Open(outputPath, FileMode.Create)) { string s = SchemaGen.Generate(typeLoader, schemaNamespace, codeNamespace, className, args); byte[] bytes = encoding.GetBytes(s); strm.Write(bytes, 0, bytes.Length); } } }
static void Main(string[] args) { string inputPath; string outputPath; string schemaNamespace; string codeNamespace; string className; bool useCacheFile = false; bool upToDate = false; if (args.Length < 4) { Console.WriteLine( "usage:\n" + "DomGen {schemaPath} {outputPath} {schemaNamespace} {classNamespace} {options}\n" + "eg: DomGen echo.xsd Schema.cs http://sce/audio Sce.Audio -a\n" + "options:\n" + "-a or -adapters\n" + " Will generate DomNodeAdapters with properties\n" + "-annotatedOnly\n" + " If the -annotatedOnly argument is set: types will be included ONLY if\n" + " <sce.domgen include=\"true\"> is defined for this type, all other types will\n" + " be skipped.\n" + " If -annotatedOnly is NOT set: types will be included by default UNLESS\n" + " <sce.domgen include=\"false\"> is explicitly set for this type" + "-enums\n" + " Will generate Enum types for all AttributeTypes which have string value restrictions\n" + "-cache\n" + " If -cache is set will generate an intermediate file and will not rebuild the output unless\n" + " the schema has changed\n"); return; } inputPath = args[0]; outputPath = args[1]; schemaNamespace = args[2]; codeNamespace = args[3]; // class name should always be the same as output file name className = Path.GetFileNameWithoutExtension(outputPath); for (int i = 4; i < args.Length; i++) { string arg = args[i]; if (arg == "-cache") useCacheFile = true; } var typeLoader = new SchemaLoader(); XmlSchema schema = null; string cacheFile = outputPath + @".dep"; // Temp: Test to see if not rebuilding speeds up our builds... if (useCacheFile && File.Exists(cacheFile)) { // Use special resolver var resolver = new HashingXmlUrlResolver(); typeLoader.SchemaResolver = resolver; schema = typeLoader.Load(inputPath); if (schema != null) { try { string previousHashString = null; using (TextReader reader = File.OpenText(cacheFile)) { previousHashString = reader.ReadLine(); } // Generate hash by concat of hash of each file stream loaded var sb = new StringBuilder(); foreach (byte[] hash in resolver.Hashes) { sb.Append(Convert.ToBase64String(hash)); } string hashString = sb.ToString(); upToDate = (previousHashString == hashString); if (upToDate == false) { using (TextWriter writer = new StreamWriter(cacheFile)) { writer.WriteLine(hashString); } } } catch (Exception) { } } } else { schema = typeLoader.Load(inputPath); } if (upToDate == false) { UTF8Encoding encoding = new UTF8Encoding(); using (FileStream strm = File.Open(outputPath, FileMode.Create)) { string s = SchemaGen.Generate(typeLoader, schemaNamespace, codeNamespace, className, args); byte[] bytes = encoding.GetBytes(s); strm.Write(bytes, 0, bytes.Length); } } }
/// <summary> /// Generates the Schema CSharp class</summary> /// <param name="typeLoader">Type loader with loaded type and annotation information</param> /// <param name="schemaNamespace">Target namespace of the schema</param> /// <param name="codeNamespace">Namespace of the class ot be generated</param> /// <param name="className">Name of the class to be generated</param> /// <param name="args">Commandline arguments</param> /// <returns>CSharp Schema class as string</returns> public static string Generate(SchemaLoader typeLoader, string schemaNamespace, string codeNamespace, string className, string[] args) { bool generateAdapters = false; bool annotatedOnly = false; bool generateEnums = false; for (int i = 4; i < args.Length; i++) { string arg = args[i]; if (arg == "-a" || arg == "-adapters") { generateAdapters = true; } else if (arg == "-annotatedOnly") { annotatedOnly = true; } else if (arg == "-enums") { generateEnums = true; } } XmlSchemaTypeCollection typeCollection = GetTypeCollection(typeLoader, schemaNamespace); string targetNamespace = typeCollection.TargetNamespace; XmlQualifiedName[] namespaces = typeCollection.Namespaces; List <DomNodeType> nodeTypes = new List <DomNodeType>(typeCollection.GetNodeTypes()); // Append additional DomNodeTypes from other namespaces, for example if the xs:import was used. // Don't include the built-in "anyType". // The reason to append is that if there is a conflict with the imported types, priority should // be given to the types defined in the importing schema file. foreach (XmlQualifiedName knownNamespace in namespaces) { if (knownNamespace.Namespace != targetNamespace && knownNamespace.Namespace != "http://www.w3.org/2001/XMLSchema") { nodeTypes.AddRange(typeCollection.GetNodeTypes(knownNamespace.Namespace)); } } List <ChildInfo> rootElements = new List <ChildInfo>(typeCollection.GetRootElements()); StringBuilder sb = new StringBuilder(); GenerateFileProlog(codeNamespace, args, sb); WriteLine(sb, " public static class {0}", className); WriteLine(sb, " {{"); WriteLine(sb, " public const string NS = \"{0}\";", targetNamespace); WriteLine(sb, ""); WriteLine(sb, " public static void Initialize(XmlSchemaTypeCollection typeCollection)"); WriteLine(sb, " {{"); WriteLine(sb, " Initialize((ns,name)=>typeCollection.GetNodeType(ns,name),"); WriteLine(sb, " (ns,name)=>typeCollection.GetRootElement(ns,name));"); WriteLine(sb, " }}"); WriteLine(sb, ""); WriteLine(sb, " public static void Initialize(IDictionary<string, XmlSchemaTypeCollection> typeCollections)"); WriteLine(sb, " {{"); WriteLine(sb, " Initialize((ns,name)=>typeCollections[ns].GetNodeType(name),"); WriteLine(sb, " (ns,name)=>typeCollections[ns].GetRootElement(name));"); WriteLine(sb, " }}"); WriteLine(sb, ""); WriteLine(sb, " private static void Initialize(Func<string, string, DomNodeType> getNodeType, Func<string, string, ChildInfo> getRootElement)"); WriteLine(sb, " {{"); StringBuilder fieldSb = new StringBuilder(); Dictionary <string, string> domNodeTypeToClassName = new Dictionary <string, string>(nodeTypes.Count); Dictionary <string, string> classNameToDomNodeType = new Dictionary <string, string>(nodeTypes.Count); foreach (DomNodeType nodeType in nodeTypes) { // Determine if the type should be included or skipped // If the -annotatedOnly argument is set: types will be included // ONLY IF <sce.domgen include="true"> is defined for this type, all other types will be skipped // If -annotatedOnly is NOT set: types will be included by default // UNLESS <sce.domgen include="false" is explicitly set for this type bool include = !annotatedOnly; XmlNode annotation; if (typeLoader.DomGenAnnotations.TryGetValue(nodeType.Name, out annotation)) { foreach (XmlAttribute attribute in annotation.Attributes) { if (attribute.Name == "include") { include = Boolean.Parse(attribute.Value); // will throw if value is not a valid boolean } } } if (!include) { continue; // skip this type if it's not to be included } string ns = codeNamespace; if (ns == null) { ns = targetNamespace; } string typeName = GetClassName(namespaces, nodeType, domNodeTypeToClassName, classNameToDomNodeType); GenerateInitializers(nodeType, typeName, sb); WriteLine(sb, ""); WriteLine(fieldSb, ""); GenerateFields(nodeType, typeName, fieldSb); } if (generateEnums) { GenerateEnums(fieldSb, typeLoader, namespaces, domNodeTypeToClassName, classNameToDomNodeType); } foreach (ChildInfo rootElement in rootElements) { string fieldName = rootElement.Name + "RootElement"; WriteLine(fieldSb, ""); WriteLine(fieldSb, " public static ChildInfo {0};", fieldName); WriteLine(sb, " {0} = getRootElement(NS, \"{1}\");", fieldName, rootElement.Name); } WriteLine(sb, " }}"); sb.Append(fieldSb.ToString()); WriteLine(sb, " }}"); if (generateAdapters) { WriteLine(sb, ""); foreach (DomNodeType nodeType in nodeTypes) { string modifiers = (nodeType.IsAbstract) ? "abstract " : ""; string adapterClassName = GetClassName(nodeType, domNodeTypeToClassName); string adapterBaseClassName = "DomNodeAdapter"; if (nodeType.BaseType != DomNodeType.BaseOfAllTypes) { adapterBaseClassName = GetClassName(nodeType.BaseType, domNodeTypeToClassName); } WriteLine(sb, " public {0}partial class {1} : {2}", modifiers, adapterClassName, adapterBaseClassName); WriteLine(sb, " {{"); foreach (AttributeInfo attrInfo in nodeType.Attributes) { if (attrInfo.DefiningType != nodeType) { continue; } string typeName = attrInfo.Type.Type.ToString(); typeName = s_attributeTypes[typeName]; string attrName = attrInfo.Name; string propertyName = attrName; if (s_cSharpKeywords.Contains(propertyName)) { propertyName = "@" + propertyName; } WriteLine(sb, " public {0} {1}", typeName, propertyName); WriteLine(sb, " {{"); string attrInfoName = className + "." + adapterClassName + "." + attrName + "Attribute"; WriteLine(sb, " get {{ return GetAttribute<{0}>({1}); }}", typeName, attrInfoName); WriteLine(sb, " set {{ SetAttribute({0}, value); }}", attrInfoName); WriteLine(sb, " }}"); } foreach (ChildInfo childInfo in nodeType.Children) { if (childInfo.DefiningType != nodeType) { continue; } string childName = childInfo.Name; string propertyName = childName; string typeName = GetClassName(childInfo.Type, domNodeTypeToClassName); string childInfoName = className + "." + adapterClassName + "." + childName + "Child"; if (childInfo.IsList) { WriteLine(sb, " public IList<{0}> {1}", typeName, propertyName); WriteLine(sb, " {{"); WriteLine(sb, " get {{ return GetChildList<{0}>({1}); }}", typeName, childInfoName); WriteLine(sb, " }}"); } else { WriteLine(sb, " public {0} {1}", typeName, propertyName); WriteLine(sb, " {{"); WriteLine(sb, " get {{ return GetChild<{0}>({1}); }}", typeName, childInfoName); WriteLine(sb, " set {{ SetChild({0}, value); }}", childInfoName); WriteLine(sb, " }}"); } } WriteLine(sb, " }}"); WriteLine(sb, ""); } } GenerateFileEpilog(sb); return(sb.ToString()); }