2 // XsdDatatypeProvider.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (c) 2004 Novell Inc.
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
35 using System.Xml.Schema;
37 using XSchema = System.Xml.Schema.XmlSchema;
39 namespace Commons.Xml.Relaxng.XmlSchema
41 public class XsdDatatypeProvider : RelaxngDatatypeProvider
43 static XsdDatatypeProvider instance = new XsdDatatypeProvider ();
44 static Hashtable table;
45 static XsdQNameWrapper qnameType = new XsdQNameWrapper ();
47 private XsdDatatypeProvider ()
52 table = new Hashtable ();
54 // TODO: fill all type names.
55 string [] names = new string [] {
61 "NMTOKEN", "NMTOKENS",
63 "ID", "IDREF", "IDREFS",
64 "ENTITY", "ENTITIES", //"NOTATION",
66 "integer", "long", "int", "short", "byte",
67 "nonPositiveInteger", "negativeInteger",
68 "nonNegativeInteger", "positiveInteger",
69 "unsignedLong", "unsignedInt",
70 "unsignedShort", "unsignedByte",
72 "base64Binary", "hexBinary",
75 "duration", "dateTime", "date", "time",
77 "gYearMonth", "gMonthDay",
78 "gYear", "gMonth", "gDay",
81 StringBuilder sb = new StringBuilder ();
82 sb.Append ("<xs:schema xmlns:xs='" + XSchema.Namespace + "'>");
83 foreach (string name in names)
84 sb.Append ("<xs:element name='" + name + "' type='xs:" + name + "'/>");
85 sb.Append ("</xs:schema>");
86 XSchema schema = XSchema.Read (new XmlTextReader (sb.ToString (), XmlNodeType.Document, null), null);
87 schema.Compile (null);
88 foreach (XmlSchemaElement el in schema.Elements.Values)
89 table.Add (el.Name, new XsdPrimitiveType (el.Name, el.ElementType as XmlSchemaDatatype));
92 public static XsdDatatypeProvider Instance {
93 get { return instance; }
96 public override RelaxngDatatype GetDatatype (string name, string ns, RelaxngParamList parameters)
98 RelaxngDatatype dt = GetPrimitiveType (name, ns);
101 else if (parameters == null || parameters.Count == 0)
104 return new XsdSimpleRestrictionType (dt, parameters);
107 private RelaxngDatatype GetPrimitiveType (string name, string ns)
110 case System.Xml.Schema.XmlSchema.Namespace:
111 case "http://www.w3.org/2001/XMLSchema-datatypes":
118 return table [name] as RelaxngDatatype;
123 public class XsdSimpleRestrictionType : RelaxngDatatype
125 XmlSchemaSimpleType type;
128 public XsdSimpleRestrictionType (RelaxngDatatype primitive, RelaxngParamList parameters)
130 type = new XmlSchemaSimpleType ();
131 XmlSchemaSimpleTypeRestriction r =
132 new XmlSchemaSimpleTypeRestriction ();
134 string ns = primitive.NamespaceURI;
135 // Remap XML Schema datatypes namespace -> XML Schema namespace.
136 if (ns == "http://www.w3.org/2001/XMLSchema-datatypes")
137 ns = XSchema.Namespace;
138 r.BaseTypeName = new XmlQualifiedName (primitive.Name, ns);
139 foreach (RelaxngParam p in parameters) {
140 XmlSchemaFacet f = null;
141 string value = p.Value;
144 f = new XmlSchemaMaxExclusiveFacet ();
147 f = new XmlSchemaMaxInclusiveFacet ();
150 f = new XmlSchemaMinExclusiveFacet ();
153 f = new XmlSchemaMinInclusiveFacet ();
156 f = new XmlSchemaPatternFacet ();
157 // .NET/Mono Regex has a bug that it does not support "IsLatin-1Supplement"
158 // (it somehow breaks at '-').
159 value = value.Replace ("\\p{IsLatin-1Supplement}", "[\\x80-\\xFF]");
162 f = new XmlSchemaWhiteSpaceFacet ();
165 f = new XmlSchemaLengthFacet ();
168 f = new XmlSchemaMaxLengthFacet ();
171 f = new XmlSchemaMinLengthFacet ();
173 case "fractionDigits":
174 f = new XmlSchemaFractionDigitsFacet ();
177 f = new XmlSchemaTotalDigitsFacet ();
180 throw new RelaxngException (String.Format ("XML Schema facet {0} is not recognized or not supported.", p.Name));
186 // Now we create XmlSchema to handle simple-type
187 // based validation (since there is no other way,
188 // because of sucky XmlSchemaSimpleType design).
189 schema = new XSchema ();
190 XmlSchemaElement el = new XmlSchemaElement ();
192 el.SchemaType = type;
193 schema.Items.Add (el);
194 schema.Compile (null);
197 public override string Name {
198 get { return type.QualifiedName.Name; }
201 public override string NamespaceURI {
202 get { return type.QualifiedName.Namespace; }
205 internal override bool IsContextDependent {
206 get { return type.Datatype != null && type.Datatype.TokenizedType == XmlTokenizedType.QName; }
209 public override object Parse (string value, XmlReader reader)
211 // Now we create XmlValidatingReader to handle
212 // simple-type based validation (since there is no
213 // other way, because of sucky XmlSchemaSimpleType
215 XmlValidatingReader v = new XmlValidatingReader (
217 String.Concat ("<root>", value, "</root>"),
218 XmlNodeType.Document,
220 v.Schemas.Add (schema);
223 return v.ReadTypedValue ();
225 v.Read (); // </root>
230 public class XsdPrimitiveType : RelaxngDatatype
232 XmlSchemaDatatype dt;
235 public XsdPrimitiveType (string name, XmlSchemaDatatype xstype)
241 internal override bool IsContextDependent {
242 get { return dt.TokenizedType == XmlTokenizedType.QName; }
245 public override string Name {
249 public override string NamespaceURI {
250 get { return "http://www.w3.org/2001/XMLSchema-datatypes"; }
253 public override object Parse (string text, XmlReader reader)
255 return dt.ParseValue (text,
256 reader != null ? reader.NameTable : null,
261 // since QName resolution will fail, it must be implemented differently.
262 public class XsdQNameWrapper : RelaxngDatatype
264 public XsdQNameWrapper ()
268 public override string Name {
269 get { return "QName"; }
272 public override string NamespaceURI {
273 get { return "http://www.w3.org/2001/XMLSchema-datatypes"; }
276 internal override bool IsContextDependent {
280 public override object Parse (string s, XmlReader reader)
282 int colonAt = s.IndexOf (':');
283 string localName = colonAt < 0 ? s : s.Substring (colonAt + 1);
284 // string localName = nameTable.Add (colonAt < 0 ? s : s.Substring (colonAt + 1));
285 return new XmlQualifiedName (localName, reader.LookupNamespace (
286 colonAt < 0 ? "" : s.Substring (0, colonAt - 1)));