536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
1057 lines
52 KiB
C#
1057 lines
52 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="XmlSchemaExporter.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
// <owner current="true" primary="true">Microsoft</owner>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Xml.Serialization {
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Xml.Schema;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
|
|
/// <include file='doc\XmlSchemaExporter.uex' path='docs/doc[@for="XmlSchemaExporter"]/*' />
|
|
///<internalonly/>
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public class XmlSchemaExporter {
|
|
internal const XmlSchemaForm elementFormDefault = XmlSchemaForm.Qualified;
|
|
internal const XmlSchemaForm attributeFormDefault = XmlSchemaForm.Unqualified;
|
|
|
|
XmlSchemas schemas;
|
|
Hashtable elements = new Hashtable(); // ElementAccessor -> XmlSchemaElement
|
|
Hashtable attributes = new Hashtable(); // AttributeAccessor -> XmlSchemaElement
|
|
Hashtable types = new Hashtable(); // StructMapping/EnumMapping -> XmlSchemaComplexType/XmlSchemaSimpleType
|
|
Hashtable references = new Hashtable(); // TypeMappings to keep track of circular references via anonymous types
|
|
bool needToExportRoot;
|
|
TypeScope scope;
|
|
|
|
/// <include file='doc\XmlSchemaExporter.uex' path='docs/doc[@for="XmlSchemaExporter.XmlSchemaExporter"]/*' />
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public XmlSchemaExporter(XmlSchemas schemas) {
|
|
this.schemas = schemas;
|
|
}
|
|
|
|
/// <include file='doc\XmlSchemaExporter.uex' path='docs/doc[@for="XmlSchemaExporter.ExportTypeMapping"]/*' />
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public void ExportTypeMapping(XmlTypeMapping xmlTypeMapping) {
|
|
xmlTypeMapping.CheckShallow();
|
|
CheckScope(xmlTypeMapping.Scope);
|
|
ExportElement(xmlTypeMapping.Accessor);
|
|
ExportRootIfNecessary(xmlTypeMapping.Scope);
|
|
}
|
|
|
|
/// <include file='doc\XmlSchemaExporter.uex' path='docs/doc[@for="XmlSchemaExporter.ExportTypeMapping1"]/*' />
|
|
public XmlQualifiedName ExportTypeMapping(XmlMembersMapping xmlMembersMapping) {
|
|
xmlMembersMapping.CheckShallow();
|
|
CheckScope(xmlMembersMapping.Scope);
|
|
MembersMapping mapping = (MembersMapping)xmlMembersMapping.Accessor.Mapping;
|
|
if (mapping.Members.Length == 1 && mapping.Members[0].Elements[0].Mapping is SpecialMapping) {
|
|
SpecialMapping special = (SpecialMapping)mapping.Members[0].Elements[0].Mapping;
|
|
XmlSchemaType type = ExportSpecialMapping(special, xmlMembersMapping.Accessor.Namespace, false, null);
|
|
if (type != null && type.Name != null && type.Name.Length > 0) {
|
|
type.Name = xmlMembersMapping.Accessor.Name;
|
|
AddSchemaItem(type, xmlMembersMapping.Accessor.Namespace, null);
|
|
}
|
|
ExportRootIfNecessary(xmlMembersMapping.Scope);
|
|
return (new XmlQualifiedName(xmlMembersMapping.Accessor.Name, xmlMembersMapping.Accessor.Namespace));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <include file='doc\XmlSchemaExporter.uex' path='docs/doc[@for="XmlSchemaExporter.ExportMembersMapping"]/*' />
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public void ExportMembersMapping(XmlMembersMapping xmlMembersMapping) {
|
|
ExportMembersMapping(xmlMembersMapping, true);
|
|
}
|
|
|
|
/// <include file='doc\XmlSchemaExporter.uex' path='docs/doc[@for="XmlSchemaExporter.ExportMembersMapping1"]/*' />
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public void ExportMembersMapping(XmlMembersMapping xmlMembersMapping, bool exportEnclosingType) {
|
|
xmlMembersMapping.CheckShallow();
|
|
MembersMapping mapping = (MembersMapping)xmlMembersMapping.Accessor.Mapping;
|
|
CheckScope(xmlMembersMapping.Scope);
|
|
if (mapping.HasWrapperElement && exportEnclosingType) {
|
|
ExportElement(xmlMembersMapping.Accessor);
|
|
}
|
|
else {
|
|
foreach (MemberMapping member in mapping.Members) {
|
|
if (member.Attribute != null)
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlBareAttributeMember, member.Attribute.Name));
|
|
else if (member.Text != null)
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlBareTextMember, member.Text.Name));
|
|
else if (member.Elements == null || member.Elements.Length == 0)
|
|
continue;
|
|
|
|
if (member.TypeDesc.IsArrayLike && !(member.Elements[0].Mapping is ArrayMapping))
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlIllegalArrayElement, member.Elements[0].Name));
|
|
|
|
if (exportEnclosingType) {
|
|
ExportElement(member.Elements[0]);
|
|
}
|
|
else {
|
|
ExportMapping(member.Elements[0].Mapping, member.Elements[0].Namespace, member.Elements[0].Any);
|
|
}
|
|
}
|
|
}
|
|
ExportRootIfNecessary(xmlMembersMapping.Scope);
|
|
}
|
|
|
|
private static XmlSchemaType FindSchemaType(string name, XmlSchemaObjectCollection items) {
|
|
// Have to loop through the items because schema.SchemaTypes has not been populated yet.
|
|
foreach (object o in items) {
|
|
XmlSchemaType type = o as XmlSchemaType;
|
|
if (type == null)
|
|
continue;
|
|
if (type.Name == name)
|
|
return type;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static bool IsAnyType(XmlSchemaType schemaType, bool mixed, bool unbounded) {
|
|
XmlSchemaComplexType complexType = schemaType as XmlSchemaComplexType;
|
|
if (complexType != null) {
|
|
if (complexType.IsMixed != mixed)
|
|
return false;
|
|
if (complexType.Particle is XmlSchemaSequence) {
|
|
XmlSchemaSequence sequence = (XmlSchemaSequence) complexType.Particle;
|
|
if (sequence.Items.Count == 1 && sequence.Items[0] is XmlSchemaAny) {
|
|
XmlSchemaAny any = (XmlSchemaAny)sequence.Items[0];
|
|
return (unbounded == any.IsMultipleOccurrence);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <include file='doc\XmlSchemaExporter.uex' path='docs/doc[@for="XmlSchemaExporter.ExportAnyType"]/*' />
|
|
public string ExportAnyType(string ns) {
|
|
string name = "any";
|
|
int i = 0;
|
|
XmlSchema schema = schemas[ns];
|
|
if (schema != null) {
|
|
while (true) {
|
|
XmlSchemaType schemaType = FindSchemaType(name, schema.Items);
|
|
if (schemaType == null)
|
|
break;
|
|
if (IsAnyType(schemaType, true, true))
|
|
return name;
|
|
i++;
|
|
name = "any" + i.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
}
|
|
|
|
XmlSchemaComplexType type = new XmlSchemaComplexType();
|
|
type.Name = name;
|
|
type.IsMixed = true;
|
|
XmlSchemaSequence seq = new XmlSchemaSequence();
|
|
XmlSchemaAny any = new XmlSchemaAny();
|
|
any.MinOccurs = 0;
|
|
any.MaxOccurs = decimal.MaxValue;
|
|
seq.Items.Add(any);
|
|
type.Particle = seq;
|
|
AddSchemaItem(type, ns, null);
|
|
return name;
|
|
}
|
|
|
|
/// <include file='doc\XmlSchemaExporter.uex' path='docs/doc[@for="XmlSchemaExporter.ExportAnyType1"]/*' />
|
|
public string ExportAnyType(XmlMembersMapping members) {
|
|
if (members.Count == 1 && members[0].Any && members[0].ElementName.Length == 0) {
|
|
XmlMemberMapping member = members[0];
|
|
string ns = member.Namespace;
|
|
bool isUnbounded = member.Mapping.TypeDesc.IsArrayLike;
|
|
bool isMixed = isUnbounded && member.Mapping.TypeDesc.ArrayElementTypeDesc != null ? member.Mapping.TypeDesc.ArrayElementTypeDesc.IsMixed : member.Mapping.TypeDesc.IsMixed;
|
|
|
|
if (isMixed && member.Mapping.TypeDesc.IsMixed)
|
|
// special case of the single top-level XmlNode --> map it to node array to match the "mixed" any type for backward compatibility
|
|
isUnbounded = true;
|
|
|
|
// generate type name, make sure that it is backward compatible
|
|
string baseName = isMixed ? "any" : isUnbounded ? "anyElements" : "anyElement";
|
|
string name = baseName;
|
|
int i = 0;
|
|
XmlSchema schema = schemas[ns];
|
|
if (schema != null) {
|
|
while (true) {
|
|
XmlSchemaType schemaType = FindSchemaType(name, schema.Items);
|
|
if (schemaType == null)
|
|
break;
|
|
if (IsAnyType(schemaType, isMixed, isUnbounded))
|
|
return name;
|
|
i++;
|
|
name = baseName + i.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
}
|
|
|
|
XmlSchemaComplexType type = new XmlSchemaComplexType();
|
|
type.Name = name;
|
|
type.IsMixed = isMixed;
|
|
XmlSchemaSequence seq = new XmlSchemaSequence();
|
|
XmlSchemaAny any = new XmlSchemaAny();
|
|
any.MinOccurs = 0;
|
|
if (isUnbounded)
|
|
any.MaxOccurs = decimal.MaxValue;
|
|
seq.Items.Add(any);
|
|
type.Particle = seq;
|
|
AddSchemaItem(type, ns, null);
|
|
return name;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
void CheckScope(TypeScope scope) {
|
|
if (this.scope == null) {
|
|
this.scope = scope;
|
|
}
|
|
else if (this.scope != scope) {
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlMappingsScopeMismatch));
|
|
}
|
|
}
|
|
|
|
XmlSchemaElement ExportElement(ElementAccessor accessor) {
|
|
if (!accessor.Mapping.IncludeInSchema && !accessor.Mapping.TypeDesc.IsRoot) {
|
|
return null;
|
|
}
|
|
if (accessor.Any && accessor.Name.Length == 0)
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlIllegalWildcard));
|
|
XmlSchemaElement element = (XmlSchemaElement)elements[accessor];
|
|
if (element != null) return element;
|
|
element = new XmlSchemaElement();
|
|
element.Name = accessor.Name;
|
|
element.IsNillable = accessor.IsNullable;
|
|
elements.Add(accessor, element);
|
|
element.Form = accessor.Form;
|
|
AddSchemaItem(element, accessor.Namespace, null);
|
|
ExportElementMapping(element, accessor.Mapping, accessor.Namespace, accessor.Any);
|
|
return element;
|
|
}
|
|
|
|
void CheckForDuplicateType(TypeMapping mapping, string newNamespace) {
|
|
if (mapping.IsAnonymousType)
|
|
return;
|
|
string newTypeName = mapping.TypeName;
|
|
XmlSchema schema = schemas[newNamespace];
|
|
if (schema != null){
|
|
foreach (XmlSchemaObject o in schema.Items) {
|
|
XmlSchemaType type = o as XmlSchemaType;
|
|
if ( type != null && type.Name == newTypeName)
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateTypeName, newTypeName, newNamespace));
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
XmlSchema AddSchema(string targetNamespace) {
|
|
XmlSchema schema = new XmlSchema();
|
|
schema.TargetNamespace = string.IsNullOrEmpty(targetNamespace) ? null : targetNamespace;
|
|
|
|
#pragma warning disable 429 // Unreachable code: the default values are constant, so will never be Unqualified
|
|
schema.ElementFormDefault = elementFormDefault == XmlSchemaForm.Unqualified ? XmlSchemaForm.None : elementFormDefault;
|
|
schema.AttributeFormDefault = attributeFormDefault == XmlSchemaForm.Unqualified ? XmlSchemaForm.None : attributeFormDefault;
|
|
#pragma warning restore 429
|
|
schemas.Add(schema);
|
|
|
|
return schema;
|
|
}
|
|
|
|
void AddSchemaItem(XmlSchemaObject item, string ns, string referencingNs) {
|
|
XmlSchema schema = schemas[ns];
|
|
if (schema == null) {
|
|
schema = AddSchema(ns);
|
|
}
|
|
|
|
if (item is XmlSchemaElement) {
|
|
XmlSchemaElement e = (XmlSchemaElement)item;
|
|
if (e.Form == XmlSchemaForm.Unqualified)
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlIllegalForm, e.Name));
|
|
e.Form = XmlSchemaForm.None;
|
|
}
|
|
else if (item is XmlSchemaAttribute) {
|
|
XmlSchemaAttribute a = (XmlSchemaAttribute)item;
|
|
if (a.Form == XmlSchemaForm.Unqualified)
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlIllegalForm, a.Name));
|
|
a.Form = XmlSchemaForm.None;
|
|
}
|
|
schema.Items.Add(item);
|
|
AddSchemaImport(ns, referencingNs);
|
|
}
|
|
|
|
void AddSchemaImport(string ns, string referencingNs) {
|
|
if (referencingNs == null) return;
|
|
if (NamespacesEqual(ns, referencingNs)) return;
|
|
XmlSchema schema = schemas[referencingNs];
|
|
if (schema == null) {
|
|
schema = AddSchema(referencingNs);
|
|
}
|
|
if (FindImport(schema, ns) == null) {
|
|
XmlSchemaImport import = new XmlSchemaImport();
|
|
if (ns != null && ns.Length > 0)
|
|
import.Namespace = ns;
|
|
schema.Includes.Add(import);
|
|
}
|
|
}
|
|
|
|
static bool NamespacesEqual(string ns1, string ns2)
|
|
{
|
|
if (ns1 == null || ns1.Length == 0)
|
|
return (ns2 == null || ns2.Length == 0);
|
|
else
|
|
return ns1 == ns2;
|
|
}
|
|
|
|
bool SchemaContainsItem(XmlSchemaObject item, string ns) {
|
|
XmlSchema schema = schemas[ns];
|
|
if (schema != null) {
|
|
return schema.Items.Contains(item);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
XmlSchemaImport FindImport(XmlSchema schema, string ns) {
|
|
foreach (object item in schema.Includes) {
|
|
if (item is XmlSchemaImport) {
|
|
XmlSchemaImport import = (XmlSchemaImport)item;
|
|
if (NamespacesEqual(import.Namespace, ns)) {
|
|
return import;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
void ExportMapping(Mapping mapping, string ns, bool isAny) {
|
|
if (mapping is ArrayMapping)
|
|
ExportArrayMapping((ArrayMapping)mapping, ns, null);
|
|
else if (mapping is PrimitiveMapping) {
|
|
ExportPrimitiveMapping((PrimitiveMapping)mapping, ns);
|
|
}
|
|
else if (mapping is StructMapping)
|
|
ExportStructMapping((StructMapping)mapping, ns, null);
|
|
else if (mapping is MembersMapping)
|
|
ExportMembersMapping((MembersMapping)mapping, ns);
|
|
else if (mapping is SpecialMapping)
|
|
ExportSpecialMapping((SpecialMapping)mapping, ns, isAny, null);
|
|
else if (mapping is NullableMapping)
|
|
ExportMapping(((NullableMapping)mapping).BaseMapping, ns, isAny);
|
|
else
|
|
throw new ArgumentException(Res.GetString(Res.XmlInternalError), "mapping");
|
|
}
|
|
|
|
void ExportElementMapping(XmlSchemaElement element, Mapping mapping, string ns, bool isAny) {
|
|
if (mapping is ArrayMapping)
|
|
ExportArrayMapping((ArrayMapping)mapping, ns, element);
|
|
else if (mapping is PrimitiveMapping) {
|
|
PrimitiveMapping pm = (PrimitiveMapping)mapping;
|
|
if (pm.IsAnonymousType) {
|
|
element.SchemaType = ExportAnonymousPrimitiveMapping(pm);
|
|
}
|
|
else {
|
|
element.SchemaTypeName = ExportPrimitiveMapping(pm, ns);
|
|
}
|
|
}
|
|
else if (mapping is StructMapping) {
|
|
ExportStructMapping((StructMapping)mapping, ns, element);
|
|
}
|
|
else if (mapping is MembersMapping)
|
|
element.SchemaType = ExportMembersMapping((MembersMapping)mapping, ns);
|
|
else if (mapping is SpecialMapping)
|
|
ExportSpecialMapping((SpecialMapping)mapping, ns, isAny, element);
|
|
else if (mapping is NullableMapping) {
|
|
ExportElementMapping(element, ((NullableMapping)mapping).BaseMapping, ns, isAny);
|
|
}
|
|
else
|
|
throw new ArgumentException(Res.GetString(Res.XmlInternalError), "mapping");
|
|
}
|
|
|
|
XmlQualifiedName ExportNonXsdPrimitiveMapping(PrimitiveMapping mapping, string ns) {
|
|
XmlSchemaSimpleType type = (XmlSchemaSimpleType)mapping.TypeDesc.DataType;
|
|
if (!SchemaContainsItem(type, UrtTypes.Namespace)) {
|
|
AddSchemaItem(type, UrtTypes.Namespace, ns);
|
|
}
|
|
else {
|
|
AddSchemaImport(mapping.Namespace, ns);
|
|
}
|
|
return new XmlQualifiedName(mapping.TypeDesc.DataType.Name, UrtTypes.Namespace);
|
|
}
|
|
|
|
XmlSchemaType ExportSpecialMapping(SpecialMapping mapping, string ns, bool isAny, XmlSchemaElement element) {
|
|
switch (mapping.TypeDesc.Kind) {
|
|
case TypeKind.Node: {
|
|
XmlSchemaComplexType type = new XmlSchemaComplexType();
|
|
type.IsMixed = mapping.TypeDesc.IsMixed;
|
|
XmlSchemaSequence seq = new XmlSchemaSequence();
|
|
XmlSchemaAny any = new XmlSchemaAny();
|
|
if (isAny) {
|
|
type.AnyAttribute = new XmlSchemaAnyAttribute();
|
|
type.IsMixed = true;
|
|
any.MaxOccurs = decimal.MaxValue;
|
|
}
|
|
seq.Items.Add(any);
|
|
type.Particle = seq;
|
|
if (element != null)
|
|
element.SchemaType = type;
|
|
return type;
|
|
}
|
|
case TypeKind.Serializable: {
|
|
SerializableMapping serializableMapping = (SerializableMapping)mapping;
|
|
if (serializableMapping.IsAny) {
|
|
XmlSchemaComplexType type = new XmlSchemaComplexType();
|
|
type.IsMixed = mapping.TypeDesc.IsMixed;
|
|
XmlSchemaSequence seq = new XmlSchemaSequence();
|
|
XmlSchemaAny any = new XmlSchemaAny();
|
|
if (isAny) {
|
|
type.AnyAttribute = new XmlSchemaAnyAttribute();
|
|
type.IsMixed = true;
|
|
any.MaxOccurs = decimal.MaxValue;
|
|
}
|
|
if (serializableMapping.NamespaceList.Length > 0)
|
|
any.Namespace = serializableMapping.NamespaceList;
|
|
any.ProcessContents = XmlSchemaContentProcessing.Lax;
|
|
|
|
if (serializableMapping.Schemas != null) {
|
|
foreach (XmlSchema schema in serializableMapping.Schemas.Schemas()) {
|
|
if (schema.TargetNamespace != XmlSchema.Namespace) {
|
|
schemas.Add(schema, true);
|
|
AddSchemaImport(schema.TargetNamespace, ns);
|
|
}
|
|
}
|
|
}
|
|
seq.Items.Add(any);
|
|
type.Particle = seq;
|
|
if (element != null)
|
|
element.SchemaType = type;
|
|
return type;
|
|
}
|
|
else if (serializableMapping.XsiType != null || serializableMapping.XsdType != null) {
|
|
XmlSchemaType type = serializableMapping.XsdType;
|
|
// for performance reasons we need to postpone merging of the serializable schemas
|
|
foreach (XmlSchema schema in serializableMapping.Schemas.Schemas()) {
|
|
if (schema.TargetNamespace != XmlSchema.Namespace) {
|
|
schemas.Add(schema, true);
|
|
AddSchemaImport(schema.TargetNamespace, ns);
|
|
if (!serializableMapping.XsiType.IsEmpty && serializableMapping.XsiType.Namespace == schema.TargetNamespace)
|
|
type = (XmlSchemaType)schema.SchemaTypes[serializableMapping.XsiType];
|
|
}
|
|
}
|
|
if (element != null) {
|
|
element.SchemaTypeName = serializableMapping.XsiType;
|
|
if (element.SchemaTypeName.IsEmpty)
|
|
element.SchemaType = type;
|
|
}
|
|
// check for duplicate top-level elements XmlAttributes
|
|
serializableMapping.CheckDuplicateElement(element, ns);
|
|
return type;
|
|
}
|
|
else if (serializableMapping.Schema != null) {
|
|
// this is the strongly-typed DataSet
|
|
XmlSchemaComplexType type = new XmlSchemaComplexType();
|
|
XmlSchemaAny any = new XmlSchemaAny();
|
|
XmlSchemaSequence seq = new XmlSchemaSequence();
|
|
seq.Items.Add(any);
|
|
type.Particle = seq;
|
|
string anyNs = serializableMapping.Schema.TargetNamespace;
|
|
any.Namespace = anyNs == null ? "" : anyNs;
|
|
XmlSchema existingSchema = schemas[anyNs];
|
|
if (existingSchema == null) {
|
|
schemas.Add(serializableMapping.Schema);
|
|
}
|
|
else if (existingSchema != serializableMapping.Schema) {
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateNamespace, anyNs));
|
|
}
|
|
if (element != null)
|
|
element.SchemaType = type;
|
|
|
|
// check for duplicate top-level elements XmlAttributes
|
|
serializableMapping.CheckDuplicateElement(element, ns);
|
|
return type;
|
|
}
|
|
else {
|
|
// DataSet
|
|
XmlSchemaComplexType type = new XmlSchemaComplexType();
|
|
XmlSchemaElement schemaElement = new XmlSchemaElement();
|
|
schemaElement.RefName = new XmlQualifiedName("schema", XmlSchema.Namespace);
|
|
XmlSchemaSequence seq = new XmlSchemaSequence();
|
|
seq.Items.Add(schemaElement);
|
|
seq.Items.Add(new XmlSchemaAny());
|
|
type.Particle = seq;
|
|
AddSchemaImport(XmlSchema.Namespace, ns);
|
|
if (element != null)
|
|
element.SchemaType = type;
|
|
return type;
|
|
}
|
|
}
|
|
default:
|
|
throw new ArgumentException(Res.GetString(Res.XmlInternalError), "mapping");
|
|
}
|
|
}
|
|
|
|
XmlSchemaType ExportMembersMapping(MembersMapping mapping, string ns) {
|
|
XmlSchemaComplexType type = new XmlSchemaComplexType();
|
|
ExportTypeMembers(type, mapping.Members, mapping.TypeName, ns, false, false);
|
|
|
|
if (mapping.XmlnsMember != null) {
|
|
AddXmlnsAnnotation(type, mapping.XmlnsMember.Name);
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
XmlSchemaType ExportAnonymousPrimitiveMapping(PrimitiveMapping mapping) {
|
|
if (mapping is EnumMapping) {
|
|
return ExportEnumMapping((EnumMapping)mapping, null);
|
|
}
|
|
else {
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Unsuported anonymous mapping type: " + mapping.ToString()));
|
|
}
|
|
}
|
|
|
|
XmlQualifiedName ExportPrimitiveMapping(PrimitiveMapping mapping, string ns) {
|
|
XmlQualifiedName qname;
|
|
if (mapping is EnumMapping) {
|
|
XmlSchemaType type = ExportEnumMapping((EnumMapping)mapping, ns);
|
|
qname = new XmlQualifiedName(type.Name, mapping.Namespace);
|
|
}
|
|
else {
|
|
if (mapping.TypeDesc.IsXsdType) {
|
|
qname = new XmlQualifiedName(mapping.TypeDesc.DataType.Name, XmlSchema.Namespace);
|
|
}
|
|
else {
|
|
qname = ExportNonXsdPrimitiveMapping(mapping, ns);
|
|
}
|
|
}
|
|
return qname;
|
|
}
|
|
|
|
void ExportArrayMapping(ArrayMapping mapping, string ns, XmlSchemaElement element) {
|
|
// some of the items in the linked list differ only by CLR type. We don't need to
|
|
// export different schema types for these. Look further down the list for another
|
|
// entry with the same elements. If there is one, it will be exported later so
|
|
// just return its name now.
|
|
|
|
ArrayMapping currentMapping = mapping;
|
|
while (currentMapping.Next != null) {
|
|
currentMapping = currentMapping.Next;
|
|
}
|
|
XmlSchemaComplexType type = (XmlSchemaComplexType) types[currentMapping];
|
|
if (type == null) {
|
|
CheckForDuplicateType(currentMapping, currentMapping.Namespace);
|
|
type = new XmlSchemaComplexType();
|
|
if (!mapping.IsAnonymousType) {
|
|
type.Name = mapping.TypeName;
|
|
AddSchemaItem(type, mapping.Namespace, ns);
|
|
}
|
|
if (!currentMapping.IsAnonymousType)
|
|
types.Add(currentMapping, type);
|
|
XmlSchemaSequence seq = new XmlSchemaSequence();
|
|
ExportElementAccessors(seq, mapping.Elements, true, false, mapping.Namespace);
|
|
if (seq.Items.Count > 0) {
|
|
#if DEBUG
|
|
// we can have only one item for the array mapping
|
|
if (seq.Items.Count != 1)
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Type " + mapping.TypeName + " from namespace '" + ns + "' is an invalid array mapping"));
|
|
#endif
|
|
if (seq.Items[0] is XmlSchemaChoice) {
|
|
type.Particle = (XmlSchemaChoice)seq.Items[0];
|
|
}
|
|
else {
|
|
type.Particle = seq;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
AddSchemaImport(mapping.Namespace, ns);
|
|
}
|
|
if (element != null) {
|
|
if (mapping.IsAnonymousType) {
|
|
element.SchemaType = type;
|
|
}
|
|
else {
|
|
element.SchemaTypeName = new XmlQualifiedName(type.Name, mapping.Namespace);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ExportElementAccessors(XmlSchemaGroupBase group, ElementAccessor[] accessors, bool repeats, bool valueTypeOptional, string ns) {
|
|
if (accessors.Length == 0) return;
|
|
if (accessors.Length == 1) {
|
|
ExportElementAccessor(group, accessors[0], repeats, valueTypeOptional, ns);
|
|
}
|
|
else {
|
|
XmlSchemaChoice choice = new XmlSchemaChoice();
|
|
choice.MaxOccurs = repeats ? decimal.MaxValue : 1;
|
|
choice.MinOccurs = repeats ? 0 : 1;
|
|
for (int i = 0; i < accessors.Length; i++)
|
|
ExportElementAccessor(choice, accessors[i], false, valueTypeOptional, ns);
|
|
|
|
if (choice.Items.Count > 0) group.Items.Add(choice);
|
|
}
|
|
}
|
|
|
|
void ExportAttributeAccessor(XmlSchemaComplexType type, AttributeAccessor accessor, bool valueTypeOptional, string ns) {
|
|
if (accessor == null) return;
|
|
XmlSchemaObjectCollection attributes;
|
|
|
|
if (type.ContentModel != null) {
|
|
if (type.ContentModel.Content is XmlSchemaComplexContentRestriction)
|
|
attributes = ((XmlSchemaComplexContentRestriction)type.ContentModel.Content).Attributes;
|
|
else if (type.ContentModel.Content is XmlSchemaComplexContentExtension)
|
|
attributes = ((XmlSchemaComplexContentExtension)type.ContentModel.Content).Attributes;
|
|
else if (type.ContentModel.Content is XmlSchemaSimpleContentExtension)
|
|
attributes = ((XmlSchemaSimpleContentExtension)type.ContentModel.Content).Attributes;
|
|
else
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlInvalidContent, type.ContentModel.Content.GetType().Name));
|
|
}
|
|
else {
|
|
attributes = type.Attributes;
|
|
}
|
|
|
|
if (accessor.IsSpecialXmlNamespace) {
|
|
|
|
// add <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
AddSchemaImport(XmlReservedNs.NsXml, ns);
|
|
|
|
// generate <xsd:attribute ref="xml:lang" use="optional" />
|
|
XmlSchemaAttribute attribute = new XmlSchemaAttribute();
|
|
attribute.Use = XmlSchemaUse.Optional;
|
|
attribute.RefName = new XmlQualifiedName(accessor.Name, XmlReservedNs.NsXml);
|
|
attributes.Add(attribute);
|
|
}
|
|
else if (accessor.Any) {
|
|
if (type.ContentModel == null) {
|
|
type.AnyAttribute = new XmlSchemaAnyAttribute();
|
|
}
|
|
else {
|
|
XmlSchemaContent content = type.ContentModel.Content;
|
|
if (content is XmlSchemaComplexContentExtension) {
|
|
XmlSchemaComplexContentExtension extension = (XmlSchemaComplexContentExtension)content;
|
|
extension.AnyAttribute = new XmlSchemaAnyAttribute();
|
|
}
|
|
else if (content is XmlSchemaComplexContentRestriction) {
|
|
XmlSchemaComplexContentRestriction restriction = (XmlSchemaComplexContentRestriction)content;
|
|
restriction.AnyAttribute = new XmlSchemaAnyAttribute();
|
|
}
|
|
else if (type.ContentModel.Content is XmlSchemaSimpleContentExtension) {
|
|
XmlSchemaSimpleContentExtension extension = (XmlSchemaSimpleContentExtension)content;
|
|
extension.AnyAttribute = new XmlSchemaAnyAttribute();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
XmlSchemaAttribute attribute = new XmlSchemaAttribute();
|
|
attribute.Use = XmlSchemaUse.None;
|
|
if (!accessor.HasDefault && !valueTypeOptional && accessor.Mapping.TypeDesc.IsValueType) {
|
|
attribute.Use = XmlSchemaUse.Required;
|
|
}
|
|
attribute.Name = accessor.Name;
|
|
if (accessor.Namespace == null || accessor.Namespace == ns) {
|
|
// determine the form attribute value
|
|
XmlSchema schema = schemas[ns];
|
|
if (schema == null)
|
|
attribute.Form = accessor.Form == attributeFormDefault ? XmlSchemaForm.None : accessor.Form;
|
|
else {
|
|
attribute.Form = accessor.Form == schema.AttributeFormDefault ? XmlSchemaForm.None : accessor.Form;
|
|
}
|
|
attributes.Add(attribute);
|
|
}
|
|
else {
|
|
// we are going to add the attribute to the top-level items. "use" attribute should not be set
|
|
if (this.attributes[accessor] == null) {
|
|
attribute.Use = XmlSchemaUse.None;
|
|
attribute.Form = accessor.Form;
|
|
AddSchemaItem(attribute, accessor.Namespace, ns);
|
|
this.attributes.Add(accessor, accessor);
|
|
}
|
|
XmlSchemaAttribute refAttribute = new XmlSchemaAttribute();
|
|
refAttribute.Use = XmlSchemaUse.None;
|
|
refAttribute.RefName = new XmlQualifiedName(accessor.Name, accessor.Namespace);
|
|
attributes.Add(refAttribute);
|
|
AddSchemaImport(accessor.Namespace, ns);
|
|
}
|
|
if (accessor.Mapping is PrimitiveMapping) {
|
|
PrimitiveMapping pm = (PrimitiveMapping)accessor.Mapping;
|
|
if (pm.IsList) {
|
|
// create local simple type for the list-like attributes
|
|
XmlSchemaSimpleType dataType = new XmlSchemaSimpleType();
|
|
XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList();
|
|
if (pm.IsAnonymousType) {
|
|
list.ItemType = (XmlSchemaSimpleType)ExportAnonymousPrimitiveMapping(pm);
|
|
}
|
|
else {
|
|
list.ItemTypeName = ExportPrimitiveMapping(pm, accessor.Namespace == null ? ns : accessor.Namespace);
|
|
}
|
|
dataType.Content = list;
|
|
attribute.SchemaType = dataType;
|
|
}
|
|
else {
|
|
if (pm.IsAnonymousType) {
|
|
attribute.SchemaType = (XmlSchemaSimpleType)ExportAnonymousPrimitiveMapping(pm);
|
|
}
|
|
else {
|
|
attribute.SchemaTypeName = ExportPrimitiveMapping(pm, accessor.Namespace == null ? ns : accessor.Namespace);
|
|
}
|
|
}
|
|
}
|
|
else if (!(accessor.Mapping is SpecialMapping))
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
|
|
|
|
if (accessor.HasDefault) {
|
|
attribute.DefaultValue = ExportDefaultValue(accessor.Mapping, accessor.Default);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ExportElementAccessor(XmlSchemaGroupBase group, ElementAccessor accessor, bool repeats, bool valueTypeOptional, string ns) {
|
|
if (accessor.Any && accessor.Name.Length == 0) {
|
|
XmlSchemaAny any = new XmlSchemaAny();
|
|
any.MinOccurs = 0;
|
|
any.MaxOccurs = repeats ? decimal.MaxValue : 1;
|
|
if (accessor.Namespace != null && accessor.Namespace.Length > 0 && accessor.Namespace != ns)
|
|
any.Namespace = accessor.Namespace;
|
|
group.Items.Add(any);
|
|
}
|
|
else {
|
|
XmlSchemaElement element = (XmlSchemaElement)elements[accessor];
|
|
int minOccurs = repeats || accessor.HasDefault || (!accessor.IsNullable && !accessor.Mapping.TypeDesc.IsValueType) || valueTypeOptional ? 0 : 1;
|
|
decimal maxOccurs = repeats || accessor.IsUnbounded ? decimal.MaxValue : 1;
|
|
|
|
if (element == null) {
|
|
element = new XmlSchemaElement();
|
|
element.IsNillable = accessor.IsNullable;
|
|
element.Name = accessor.Name;
|
|
if (accessor.HasDefault)
|
|
element.DefaultValue = ExportDefaultValue(accessor.Mapping, accessor.Default);
|
|
|
|
if (accessor.IsTopLevelInSchema) {
|
|
elements.Add(accessor, element);
|
|
element.Form = accessor.Form;
|
|
AddSchemaItem(element, accessor.Namespace, ns);
|
|
}
|
|
else {
|
|
element.MinOccurs = minOccurs;
|
|
element.MaxOccurs = maxOccurs;
|
|
// determine the form attribute value
|
|
XmlSchema schema = schemas[ns];
|
|
if (schema == null)
|
|
element.Form = accessor.Form == elementFormDefault ? XmlSchemaForm.None : accessor.Form;
|
|
else {
|
|
element.Form = accessor.Form == schema.ElementFormDefault ? XmlSchemaForm.None : accessor.Form;
|
|
}
|
|
}
|
|
ExportElementMapping(element, (TypeMapping)accessor.Mapping, accessor.Namespace, accessor.Any);
|
|
}
|
|
if (accessor.IsTopLevelInSchema) {
|
|
XmlSchemaElement refElement = new XmlSchemaElement();
|
|
refElement.RefName = new XmlQualifiedName(accessor.Name, accessor.Namespace);
|
|
refElement.MinOccurs = minOccurs;
|
|
refElement.MaxOccurs = maxOccurs;
|
|
group.Items.Add(refElement);
|
|
AddSchemaImport(accessor.Namespace, ns);
|
|
}
|
|
else {
|
|
group.Items.Add(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
static internal string ExportDefaultValue(TypeMapping mapping, object value) {
|
|
|
|
if (!(mapping is PrimitiveMapping))
|
|
// should throw, but it will be a breaking change;
|
|
return null;
|
|
|
|
if (value == null || value == DBNull.Value)
|
|
return null;
|
|
|
|
if (mapping is EnumMapping) {
|
|
EnumMapping em = (EnumMapping)mapping;
|
|
|
|
#if DEBUG
|
|
// use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
|
|
if (value.GetType() != typeof(string)) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, Res.GetString(Res.XmlInvalidDefaultValue, value.ToString(), value.GetType().FullName)));
|
|
#endif
|
|
|
|
// check the validity of the value
|
|
ConstantMapping[] c = em.Constants;
|
|
if (em.IsFlags) {
|
|
string[] names = new string[c.Length];
|
|
long[] ids = new long[c.Length];
|
|
Hashtable values = new Hashtable();
|
|
for (int i = 0; i < c.Length; i++) {
|
|
names[i] = c[i].XmlName;
|
|
ids[i] = 1 << i;
|
|
values.Add(c[i].Name, ids[i]);
|
|
}
|
|
long val = XmlCustomFormatter.ToEnum((string)value, values, em.TypeName, false);
|
|
return val != 0 ? XmlCustomFormatter.FromEnum(val, names, ids, mapping.TypeDesc.FullName) : null;
|
|
}
|
|
else {
|
|
for (int i = 0; i < c.Length; i++) {
|
|
if (c[i].Name == (string)value) {
|
|
return c[i].XmlName;
|
|
}
|
|
}
|
|
return null; // unknown value
|
|
}
|
|
}
|
|
|
|
PrimitiveMapping pm = (PrimitiveMapping)mapping;
|
|
|
|
if (!pm.TypeDesc.HasCustomFormatter) {
|
|
|
|
#if DEBUG
|
|
// use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
|
|
if (pm.TypeDesc.Type == null) {
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Mapping for " + pm.TypeDesc.Name + " missing type property"));
|
|
}
|
|
#endif
|
|
|
|
if (pm.TypeDesc.FormatterName == "String")
|
|
return (string)value;
|
|
|
|
Type formatter = typeof(XmlConvert);
|
|
System.Reflection.MethodInfo format = formatter.GetMethod("ToString", new Type[] { pm.TypeDesc.Type });
|
|
if (format != null)
|
|
return (string)format.Invoke(formatter, new Object[] {value});
|
|
}
|
|
else {
|
|
string defaultValue = XmlCustomFormatter.FromDefaultValue(value, pm.TypeDesc.FormatterName);
|
|
if (defaultValue == null)
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDefaultValue, value.ToString(), pm.TypeDesc.Name));
|
|
return defaultValue;
|
|
}
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDefaultValue, value.ToString(), pm.TypeDesc.Name));
|
|
}
|
|
|
|
void ExportRootIfNecessary(TypeScope typeScope) {
|
|
if (!needToExportRoot)
|
|
return;
|
|
foreach (TypeMapping mapping in typeScope.TypeMappings) {
|
|
if (mapping is StructMapping && mapping.TypeDesc.IsRoot) {
|
|
ExportDerivedMappings((StructMapping) mapping);
|
|
}
|
|
else if (mapping is ArrayMapping) {
|
|
ExportArrayMapping((ArrayMapping) mapping, mapping.Namespace, null);
|
|
}
|
|
else if (mapping is SerializableMapping) {
|
|
ExportSpecialMapping((SerializableMapping)mapping, mapping.Namespace, false, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
XmlQualifiedName ExportStructMapping(StructMapping mapping, string ns, XmlSchemaElement element) {
|
|
if (mapping.TypeDesc.IsRoot) {
|
|
needToExportRoot = true;
|
|
return XmlQualifiedName.Empty;
|
|
}
|
|
if (mapping.IsAnonymousType) {
|
|
if (references[mapping] != null)
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlCircularReference2, mapping.TypeDesc.Name, "AnonymousType", "false"));
|
|
references[mapping] = mapping;
|
|
}
|
|
XmlSchemaComplexType type = (XmlSchemaComplexType)types[mapping];
|
|
if (type == null) {
|
|
if (!mapping.IncludeInSchema) throw new InvalidOperationException(Res.GetString(Res.XmlCannotIncludeInSchema, mapping.TypeDesc.Name));
|
|
CheckForDuplicateType(mapping, mapping.Namespace);
|
|
type = new XmlSchemaComplexType();
|
|
if (!mapping.IsAnonymousType) {
|
|
type.Name = mapping.TypeName;
|
|
AddSchemaItem(type, mapping.Namespace, ns);
|
|
types.Add(mapping, type);
|
|
}
|
|
type.IsAbstract = mapping.TypeDesc.IsAbstract;
|
|
bool openModel = mapping.IsOpenModel;
|
|
if (mapping.BaseMapping != null && mapping.BaseMapping.IncludeInSchema) {
|
|
if (mapping.BaseMapping.IsAnonymousType) {
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlAnonymousBaseType, mapping.TypeDesc.Name, mapping.BaseMapping.TypeDesc.Name, "AnonymousType", "false"));
|
|
}
|
|
if (mapping.HasSimpleContent) {
|
|
XmlSchemaSimpleContent model = new XmlSchemaSimpleContent();
|
|
XmlSchemaSimpleContentExtension extension = new XmlSchemaSimpleContentExtension();
|
|
extension.BaseTypeName = ExportStructMapping(mapping.BaseMapping, mapping.Namespace, null);
|
|
model.Content = extension;
|
|
type.ContentModel = model;
|
|
}
|
|
else {
|
|
XmlSchemaComplexContentExtension extension = new XmlSchemaComplexContentExtension();
|
|
extension.BaseTypeName = ExportStructMapping(mapping.BaseMapping, mapping.Namespace, null);
|
|
XmlSchemaComplexContent model = new XmlSchemaComplexContent();
|
|
model.Content = extension;
|
|
model.IsMixed = XmlSchemaImporter.IsMixed((XmlSchemaComplexType)types[mapping.BaseMapping]);
|
|
type.ContentModel = model;
|
|
}
|
|
openModel = false;
|
|
}
|
|
ExportTypeMembers(type, mapping.Members, mapping.TypeName, mapping.Namespace, mapping.HasSimpleContent, openModel);
|
|
ExportDerivedMappings(mapping);
|
|
if (mapping.XmlnsMember != null) {
|
|
AddXmlnsAnnotation(type, mapping.XmlnsMember.Name);
|
|
}
|
|
}
|
|
else {
|
|
AddSchemaImport(mapping.Namespace, ns);
|
|
}
|
|
if (mapping.IsAnonymousType) {
|
|
references[mapping] = null;
|
|
if (element != null)
|
|
element.SchemaType = type;
|
|
return XmlQualifiedName.Empty;
|
|
}
|
|
else {
|
|
XmlQualifiedName qname = new XmlQualifiedName(type.Name, mapping.Namespace);
|
|
if (element != null) element.SchemaTypeName = qname;
|
|
return qname;
|
|
}
|
|
}
|
|
|
|
void ExportTypeMembers(XmlSchemaComplexType type, MemberMapping[] members, string name, string ns, bool hasSimpleContent, bool openModel) {
|
|
XmlSchemaGroupBase seq = new XmlSchemaSequence();
|
|
TypeMapping textMapping = null;
|
|
|
|
for (int i = 0; i < members.Length; i++) {
|
|
MemberMapping member = members[i];
|
|
if (member.Ignore)
|
|
continue;
|
|
if (member.Text != null) {
|
|
if (textMapping != null) {
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlIllegalMultipleText, name));
|
|
}
|
|
textMapping = member.Text.Mapping;
|
|
}
|
|
if (member.Elements.Length > 0) {
|
|
bool repeats = member.TypeDesc.IsArrayLike &&
|
|
!(member.Elements.Length == 1 && member.Elements[0].Mapping is ArrayMapping);
|
|
|
|
bool valueTypeOptional = member.CheckSpecified != SpecifiedAccessor.None || member.CheckShouldPersist;
|
|
ExportElementAccessors(seq, member.Elements, repeats, valueTypeOptional, ns);
|
|
}
|
|
}
|
|
|
|
if (seq.Items.Count > 0) {
|
|
if (type.ContentModel != null) {
|
|
if (type.ContentModel.Content is XmlSchemaComplexContentRestriction)
|
|
((XmlSchemaComplexContentRestriction)type.ContentModel.Content).Particle = seq;
|
|
else if (type.ContentModel.Content is XmlSchemaComplexContentExtension)
|
|
((XmlSchemaComplexContentExtension)type.ContentModel.Content).Particle = seq;
|
|
else
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlInvalidContent, type.ContentModel.Content.GetType().Name));
|
|
}
|
|
else {
|
|
type.Particle = seq;
|
|
}
|
|
}
|
|
if (textMapping != null) {
|
|
if (hasSimpleContent) {
|
|
if (textMapping is PrimitiveMapping && seq.Items.Count == 0) {
|
|
PrimitiveMapping pm = (PrimitiveMapping)textMapping;
|
|
if (pm.IsList) {
|
|
type.IsMixed = true;
|
|
}
|
|
else {
|
|
if (pm.IsAnonymousType) {
|
|
throw new InvalidOperationException(Res.GetString(Res.XmlAnonymousBaseType, textMapping.TypeDesc.Name, pm.TypeDesc.Name, "AnonymousType", "false"));
|
|
}
|
|
// Create simpleContent
|
|
XmlSchemaSimpleContent model = new XmlSchemaSimpleContent();
|
|
XmlSchemaSimpleContentExtension ex = new XmlSchemaSimpleContentExtension();
|
|
model.Content = ex;
|
|
type.ContentModel = model;
|
|
ex.BaseTypeName = ExportPrimitiveMapping(pm, ns);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
type.IsMixed = true;
|
|
}
|
|
}
|
|
bool anyAttribute = false;
|
|
for (int i = 0; i < members.Length; i++) {
|
|
AttributeAccessor accessor = members[i].Attribute;
|
|
if (accessor != null) {
|
|
ExportAttributeAccessor(type, members[i].Attribute, members[i].CheckSpecified != SpecifiedAccessor.None || members[i].CheckShouldPersist, ns);
|
|
if (members[i].Attribute.Any)
|
|
anyAttribute = true;
|
|
}
|
|
}
|
|
if (openModel && !anyAttribute) {
|
|
AttributeAccessor any = new AttributeAccessor();
|
|
any.Any = true;
|
|
ExportAttributeAccessor(type, any, false, ns);
|
|
}
|
|
}
|
|
|
|
void ExportDerivedMappings(StructMapping mapping) {
|
|
if (mapping.IsAnonymousType)
|
|
return;
|
|
for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
|
|
if (derived.IncludeInSchema) ExportStructMapping(derived, derived.Namespace, null);
|
|
}
|
|
}
|
|
|
|
XmlSchemaType ExportEnumMapping(EnumMapping mapping, string ns) {
|
|
if (!mapping.IncludeInSchema) throw new InvalidOperationException(Res.GetString(Res.XmlCannotIncludeInSchema, mapping.TypeDesc.Name));
|
|
XmlSchemaSimpleType dataType = (XmlSchemaSimpleType)types[mapping];
|
|
if (dataType == null) {
|
|
CheckForDuplicateType(mapping, mapping.Namespace);
|
|
dataType = new XmlSchemaSimpleType();
|
|
dataType.Name = mapping.TypeName;
|
|
if (!mapping.IsAnonymousType) {
|
|
types.Add(mapping, dataType);
|
|
AddSchemaItem(dataType, mapping.Namespace, ns);
|
|
}
|
|
XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction();
|
|
restriction.BaseTypeName = new XmlQualifiedName("string", XmlSchema.Namespace);
|
|
|
|
for (int i = 0; i < mapping.Constants.Length; i++) {
|
|
ConstantMapping constant = mapping.Constants[i];
|
|
XmlSchemaEnumerationFacet enumeration = new XmlSchemaEnumerationFacet();
|
|
enumeration.Value = constant.XmlName;
|
|
restriction.Facets.Add(enumeration);
|
|
}
|
|
if (!mapping.IsFlags) {
|
|
dataType.Content = restriction;
|
|
}
|
|
else {
|
|
XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList();
|
|
XmlSchemaSimpleType enumType = new XmlSchemaSimpleType();
|
|
enumType.Content = restriction;
|
|
list.ItemType = enumType;
|
|
dataType.Content = list;
|
|
}
|
|
}
|
|
if (!mapping.IsAnonymousType) {
|
|
AddSchemaImport(mapping.Namespace, ns);
|
|
}
|
|
return dataType;
|
|
}
|
|
|
|
void AddXmlnsAnnotation(XmlSchemaComplexType type, string xmlnsMemberName) {
|
|
XmlSchemaAnnotation annotation = new XmlSchemaAnnotation();
|
|
XmlSchemaAppInfo appinfo = new XmlSchemaAppInfo();
|
|
|
|
XmlDocument d = new XmlDocument();
|
|
XmlElement e = d.CreateElement("keepNamespaceDeclarations");
|
|
if (xmlnsMemberName != null)
|
|
e.InsertBefore(d.CreateTextNode(xmlnsMemberName), null);
|
|
appinfo.Markup = new XmlNode[] {e};
|
|
annotation.Items.Add(appinfo);
|
|
type.Annotation = annotation;
|
|
}
|
|
}
|
|
}
|