1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
//------------------------------------------------------------------------------
// <copyright file="ShapeGenerator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">derekdb</owner>
//------------------------------------------------------------------------------
#if ENABLEDATABINDING
using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Collections;
using System.Diagnostics;
using System.ComponentModel;
using System.Text;
namespace System.Xml.XPath.DataBinding
{
internal sealed class ShapeGenerator
{
private Hashtable elementTypesProcessed;
private IXmlNamespaceResolver nsResolver;
public ShapeGenerator(IXmlNamespaceResolver nsResolver) {
this.elementTypesProcessed = new Hashtable();
this.nsResolver = nsResolver;
}
public Shape GenerateFromSchema(XmlSchemaElement xse) {
XmlQualifiedName xseName = xse.QualifiedName;
XmlSchemaType schemaType = xse.ElementSchemaType;
XmlSchemaComplexType complexType = schemaType as XmlSchemaComplexType;
if (null != complexType) {
XmlSchemaParticle particle = null;
Shape rootShape = null;
XmlSchemaContentType contentType = complexType.ElementDecl.ContentValidator.ContentType;
switch (contentType) {
case XmlSchemaContentType.Mixed:
case XmlSchemaContentType.TextOnly:
rootShape = new Shape(GenName(xseName) + "_Text", BindingType.Text);
rootShape.AddParticle(xse);
break;
case XmlSchemaContentType.Empty:
rootShape = new Shape(null, BindingType.Sequence);
break;
case XmlSchemaContentType.ElementOnly:
particle = complexType.ContentTypeParticle;
rootShape = ProcessParticle(particle, null);
break;
}
Debug.Assert(rootShape != null);
if (complexType.AttributeUses.Values.Count > 0) {
if (rootShape.BindingType != BindingType.Sequence) {
Shape s = new Shape(null, BindingType.Sequence);
s.AddSubShape(rootShape);
rootShape = s;
}
int pos = 0;
string[] names = rootShape.SubShapeNames();
ICollection attributes = complexType.AttributeUses.Values;
XmlSchemaAttribute[] xsaArray = new XmlSchemaAttribute[attributes.Count];
attributes.CopyTo(xsaArray, 0);
Array.Sort(xsaArray, new XmlSchemaAttributeComparer());
foreach(XmlSchemaAttribute xsa in xsaArray) {
string name = GenAttrName(xsa.QualifiedName, names);
Shape attrShape = new Shape(name, BindingType.Attribute);
attrShape.AddParticle(xsa);
rootShape.AddAttrShapeAt(attrShape, pos++);
}
}
if (rootShape.BindingType != BindingType.Text) {
rootShape.Name = GenName(xseName);
rootShape.ContainerDecl = xse;
}
return rootShape;
}
else { // simple type
Shape s = new Shape(GenName(xseName), BindingType.Text);
s.AddParticle(xse);
return s;
}
}
public Shape GenerateFromSchema(XmlSchemaAttribute xsa) {
Shape s = new Shape(GenName(xsa.QualifiedName), BindingType.Attribute);
s.AddParticle(xsa);
return s;
}
Shape ProcessParticle(XmlSchemaParticle xsp, Shape parent) {
Shape s;
if (xsp == XmlSchemaParticle.Empty) {
return null;
}
if (xsp is XmlSchemaElement) {
s = ProcessParticleElement((XmlSchemaElement)xsp);
}
else if (xsp is XmlSchemaSequence) {
s = ProcessParticleGroup((XmlSchemaSequence)xsp, BindingType.Sequence);
}
else if (xsp is XmlSchemaChoice) {
s = ProcessParticleGroup((XmlSchemaChoice)xsp, BindingType.Choice);
}
else if (xsp is XmlSchemaAll) {
s = ProcessParticleGroup((XmlSchemaAll)xsp, BindingType.All);
}
else { //XmlSchemaAny
return null; //Ignore Any in the content model
}
if (xsp.MaxOccurs > 1) {
Shape rep = new Shape(s.Name, BindingType.Repeat);
rep.AddSubShape(s);
s = rep;
}
if (parent != null)
parent.AddSubShape(s);
return s;
}
Shape ProcessParticleElement(XmlSchemaElement xse) {
// watch out for recursive schema
Shape s = (Shape)this.elementTypesProcessed[xse];
if (null != s)
return s;
bool complex = xse.ElementSchemaType is XmlSchemaComplexType;
s = new Shape(GenName(xse.QualifiedName), complex ? BindingType.ElementNested : BindingType.Element);
s.AddParticle(xse);
if (complex) {
this.elementTypesProcessed.Add(xse, s);
s.NestedShape = GenerateFromSchema(xse);
this.elementTypesProcessed.Remove(xse);
}
return s;
}
Shape ProcessParticleGroup(XmlSchemaGroupBase xsg, BindingType bt) {
Shape s = new Shape(null, bt);
StringBuilder sb = new StringBuilder();
foreach (XmlSchemaParticle xsp in xsg.Items) {
Shape sub = ProcessParticle(xsp, s);
if (sub != null) { //sub can be null if the child particle is xs:any
if (sb.Length > 0)
sb.Append('_');
sb.Append(sub.Name);
}
}
// need to also test if paretn != null for this to work
//if (s.IsGroup && s.SubShapes.Count == 1) {
// Shape sub = (Shape)s.SubShapes[0];
// s.Clear();
// return sub;
//}
s.Name = sb.ToString();
return s;
}
string GenName(XmlQualifiedName xqn) {
string ns = xqn.Namespace;
string ln = xqn.Name;
if (ns.Length != 0) {
string prefix = (null==this.nsResolver) ? null : this.nsResolver.LookupPrefix(ns);
if (prefix != null && prefix.Length != 0)
return String.Concat(prefix, ":", ln);
}
return ln;
}
string GenAttrName(XmlQualifiedName xqn, string[] names) {
string name = GenName(xqn);
if (null != names) {
for (int i=0; i<names.Length; i++) {
if (name == names[i]) {
return String.Concat("@", name);
}
}
}
return name;
}
public void ResetState() {
this.elementTypesProcessed.Clear();
}
class XmlSchemaAttributeComparer : IComparer {
public virtual int Compare(object a, object b) {
XmlSchemaAttribute xsaA = (XmlSchemaAttribute)a;
XmlSchemaAttribute xsaB = (XmlSchemaAttribute)b;
return XmlQualifiedName.Compare(xsaA.QualifiedName, xsaB.QualifiedName);
}
}
}
}
#endif
|