+2010-04-16 Atsushi Enomoto <atsushi@ximian.com>
+
+ * XamlXmlReader.cs : Resolve generic type names. Process attribute
+ members.
+ * XamlLanguage.cs : add XamlTypeName-to-ClrType method.
+ * XmlSchemaContext.cs : extracted special type name handling to above.
+
2010-04-16 Atsushi Enomoto <atsushi@ximian.com>
* XamlType.cs : sort of reverted AllowedContentTypes.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
+using System.Linq;
using System.Reflection;
using System.Xaml.Schema;
using System.Windows.Markup;
}
}
+ internal static XamlType GetSpecialXaml2006Type (string name)
+ {
+ // FIXME: I'm not really sure if these *special* names
+ // should be resolved here and there. There just does
+ // not seem to be any other appropriate places.
+ switch (name) {
+ case "Array":
+ return XamlLanguage.Array;
+ case "Member":
+ return XamlLanguage.Member;
+ case "Null":
+ return XamlLanguage.Null;
+ case "Property":
+ return XamlLanguage.Property;
+ case "Static":
+ return XamlLanguage.Static;
+ case "Type":
+ return XamlLanguage.Type;
+ }
+ return null;
+ }
+
static readonly int clr_ns_len = "clr-namespace:".Length;
static readonly int clr_ass_len = "assembly=".Length;
- internal static Type ParseClrTypeName (string xmlNamespace, string xmlLocalName)
+ internal static Type ResolveXamlTypeName (string xmlNamespace, string xmlLocalName, IList<XamlTypeName> typeArguments, IXamlNamespaceResolver nsResolver)
{
string ns = xmlNamespace;
string name = xmlLocalName;
- if (!ns.StartsWith ("clr-namespace:", StringComparison.Ordinal))
- return null;
+ if (ns == XamlLanguage.Xaml2006Namespace) {
+ var xt = GetSpecialXaml2006Type (name);
+ if (xt == null)
+ xt = AllTypes.FirstOrDefault (t => t.Name == xmlLocalName);
+ if (xt == null)
+ throw new FormatException (string.Format ("There is no type '{0}' in XAML namespace", name));
+ return xt.UnderlyingType;
+ }
+ else if (!ns.StartsWith ("clr-namespace:", StringComparison.Ordinal))
+ throw new FormatException (string.Format ("Unexpected XAML namespace '{0}'", ns));
+
+ Type [] genArgs = null;
+ if (typeArguments != null) {
+ var xtns = typeArguments;
+ genArgs = new Type [xtns.Count];
+ for (int i = 0; i < genArgs.Length; i++) {
+ var xtn = xtns [i];
+ genArgs [i] = ResolveXamlTypeName (xtn.Namespace, xtn.Name, xtn.TypeArguments, nsResolver);
+ }
+ }
+ // convert xml namespace to clr namespace and assembly
string [] split = ns.Split (';');
if (split.Length != 2 || split [0].Length <= clr_ns_len || split [1].Length <= clr_ass_len)
throw new XamlParseException (string.Format ("Cannot resolve runtime namespace from XML namespace '{0}'", ns));
- var tns = split [0].Substring (clr_ns_len);
- var tan = split [1].Substring (clr_ass_len);
- string aqn = (tns.Length > 0 ? tns + '.' + name : name) + (tan.Length > 0 ? ", " + tan : string.Empty);
- return System.Type.GetType (aqn);
+ string tns = split [0].Substring (clr_ns_len);
+ string aname = split [1].Substring (clr_ass_len);
+
+ string tfn = tns.Length > 0 ? tns + '.' + name : name;
+ if (genArgs != null)
+ tfn += "`" + genArgs.Length;
+ string taqn = tfn + (aname.Length > 0 ? ", " + aname : string.Empty);
+ var ret = System.Type.GetType (taqn);
+ if (ret == null)
+ throw new XamlParseException (string.Format ("Cannot resolve runtime type from XML namespace '{0}', local name '{1}' with {2} type arguments ({3})", ns, name, typeArguments.Count, taqn));
+ return genArgs == null ? ret : ret.MakeGenericType (genArgs);
}
}
}
XamlType ret;
if (xamlNamespace == XamlLanguage.Xaml2006Namespace) {
- // FIXME: I'm not really sure if these *special*
- // names should be resolved here. There just
- // does not seem to be any other appropriate
- // places.
- switch (name) {
- case "Array":
- return XamlLanguage.Array;
- case "Member":
- return XamlLanguage.Member;
- case "Null":
- return XamlLanguage.Null;
- case "Property":
- return XamlLanguage.Property;
- case "Static":
- return XamlLanguage.Static;
- case "Type":
- return XamlLanguage.Type;
- }
- ret = XamlLanguage.AllTypes.FirstOrDefault (t => TypeMatches (t, xamlNamespace, name, typeArguments));
+ ret = XamlLanguage.GetSpecialXaml2006Type (name);
+ if (ret == null)
+ ret = XamlLanguage.AllTypes.FirstOrDefault (t => TypeMatches (t, xamlNamespace, name, typeArguments));
if (ret != null)
return ret;
}
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Xml;
using System.Xaml.Schema;
-using Pair = System.Collections.Generic.KeyValuePair<System.Xaml.XamlDirective,object>;
+using Pair = System.Collections.Generic.KeyValuePair<System.Xaml.XamlMember,string>;
namespace System.Xaml
{
// FIXME: is GetObject supported by this reader?
public class XamlXmlReader : XamlReader, IXamlLineInfo
{
+ #region constructors
+
public XamlXmlReader (Stream stream)
: this (stream, (XamlXmlReaderSettings) null)
{
r = XmlReader.Create (xmlReader, xrs);
line_info = r as IXmlLineInfo;
+ xaml_namespace_resolver = new NamespaceResolver (r as IXmlNamespaceResolver);
}
+
+ #endregion
XmlReader r;
IXmlLineInfo line_info;
object current;
bool inside_object_not_member, is_empty_object, is_empty_member;
- List<XamlTypeName> type_args = new List<XamlTypeName> ();
Stack<XamlType> types = new Stack<XamlType> ();
XamlMember current_member;
- List<Pair> current_element_directives = new List<Pair> ();
- IEnumerator<Pair> current_directive_enumerator;
+ List<Pair> stored_members = new List<Pair> ();
+ IEnumerator<Pair> stored_member_enumerator;
+ IXamlNamespaceResolver xaml_namespace_resolver;
public bool HasLineInfo {
get { return line_info != null && line_info.HasLineInfo (); }
if (is_eof)
return false;
+ // check this before is_empty_* so that they aren't ignored.
+ if (MoveToNextAttributeMember ())
+ return true;
+
if (is_empty_object) {
is_empty_object = false;
ReadEndType ();
return true;
}
- if (CheckCurrentDirective ())
- return true;
-
if (!r.EOF)
r.MoveToContent ();
if (r.EOF) {
{
string name = r.LocalName;
string ns = r.NamespaceURI;
- type_args.Clear ();
- CollectDirectiveAttributes ();
+ string typeArgNames = null;
+ var atts = ProcessAttributes ();
if (!r.IsEmptyElement) {
r.Read ();
break;
default:
// this value is for Initialization
- current_element_directives.Add (new Pair (XamlLanguage.Initialization, r.Value));
+ // FIXME: this could also be a WrappedContents
+ stored_members.Add (new Pair (XamlLanguage.Initialization, r.Value));
r.Read ();
continue;
}
else
is_empty_object = true;
- XamlType xt;
- if (ns.StartsWith ("clr-namespace:", StringComparison.Ordinal)) {
- Type rtype = XamlLanguage.ParseClrTypeName (ns, name);
- if (rtype == null)
- throw new XamlParseException (String.Format ("Cannot resolve runtime namespace from XML namespace '{0}' and local name '{1}'", ns, name));
- xt = sctx.GetXamlType (rtype);
+ // check TypeArguments to resolve Type, and remove them from the list. They don't appear as a node.
+ foreach (var p in stored_members) {
+ if (p.Key == XamlLanguage.TypeArguments) {
+ typeArgNames = p.Value;
+ stored_members.Remove (p);
+ break;
+ }
}
- else
- xt = sctx.GetXamlType (new XamlTypeName (ns, name, type_args.ToArray ()));
+
+ XamlType xt;
+ IList<XamlTypeName> typeArgs = typeArgNames == null ? null : XamlTypeName.ParseList (typeArgNames, xaml_namespace_resolver);
+ Type rtype = XamlLanguage.ResolveXamlTypeName (ns, name, typeArgs, xaml_namespace_resolver);
+ if (rtype == null)
+ throw new XamlParseException (String.Format ("Cannot resolve runtime namespace from XML namespace '{0}', local name '{1}' and type argument '{2}'", ns, name, typeArgNames));
+ xt = sctx.GetXamlType (rtype);
if (xt == null)
// FIXME: .NET just treats the node as empty!
// we have to sort out what to do here.
types.Push (xt);
current = xt;
+ foreach (var p in atts) {
+ var xm = xt.GetMember (p.Key);
+ if (xm != null)
+ stored_members.Add (new Pair (xm, p.Value));
+ // ignore unknown attribute
+ }
+
node_type = XamlNodeType.StartObject;
inside_object_not_member = true;
// The next Read() results are likely directives.
- current_directive_enumerator = current_element_directives.GetEnumerator ();
+ stored_member_enumerator = stored_members.GetEnumerator ();
}
void ReadStartMember ()
node_type = XamlNodeType.Value;
}
- void CollectDirectiveAttributes ()
+ // returns remaining attributes to be processed
+ Dictionary<string,string> ProcessAttributes ()
{
- var l = current_element_directives;
- if (types.Count == 0 && r.BaseURI != null) // top
- l.Add (new Pair (XamlLanguage.Base, r.BaseURI));
+ var l = stored_members;
+
+ // base
+ string xmlbase = r.GetAttribute ("base", XamlLanguage.Xml1998Namespace) ?? r.BaseURI;
+ if (types.Count == 0 && xmlbase != null) // top
+ l.Add (new Pair (XamlLanguage.Base, xmlbase));
+
+ var atts = new Dictionary<string,string> ();
+
+ if (r.MoveToFirstAttribute ()) {
+ do {
+ if (r.NamespaceURI == XamlLanguage.Xmlns2000Namespace)
+ continue;
+ XamlDirective d = XamlLanguage.AllDirectives.FirstOrDefault (dd => (dd.AllowedLocation & AllowedMemberLocations.Attribute) != 0 && dd.Name == r.LocalName);
+ if (d != null) {
+ l.Add (new Pair (d, r.Value));
+ continue;
+ }
+ if (r.NamespaceURI == String.Empty) {
+ atts.Add (r.LocalName, r.Value);
+ continue;
+ }
+ // Should we just ignore unknown attribute in XAML namespace or any other namespaces ?
+ // Probably yes for compatibility with future version.
+ } while (r.MoveToNextAttribute ());
+ r.MoveToElement ();
+ }
+ return atts;
}
- bool CheckCurrentDirective ()
+ bool MoveToNextAttributeMember ()
{
- if (current_directive_enumerator != null) {
+ if (stored_member_enumerator != null) {
// FIXME: value might have to be deserialized.
switch (node_type) {
case XamlNodeType.StartObject:
case XamlNodeType.EndMember:
// -> StartMember
- if (current_directive_enumerator.MoveNext ()) {
- current = current_member = current_directive_enumerator.Current.Key;
+ if (stored_member_enumerator.MoveNext ()) {
+ current = current_member = stored_member_enumerator.Current.Key;
node_type = XamlNodeType.StartMember;
return true;
}
break;
case XamlNodeType.StartMember:
// -> Value
- current = current_directive_enumerator.Current.Value;
+ current = stored_member_enumerator.Current.Value;
node_type = XamlNodeType.Value;
return true;
case XamlNodeType.Value:
}
}
- current_element_directives.Clear ();
- current_directive_enumerator = null;
+ stored_members.Clear ();
+ stored_member_enumerator = null;
return false;
}
{
return HasLineInfo ? String.Format (" Line {0}, at {1}", LineNumber, LinePosition) : String.Empty;
}
+
+ class NamespaceResolver : IXamlNamespaceResolver
+ {
+ IXmlNamespaceResolver source;
+
+ public NamespaceResolver (IXmlNamespaceResolver source)
+ {
+ this.source = source;
+ }
+
+ public string GetNamespace (string prefix)
+ {
+ return source.LookupNamespace (prefix);
+ }
+
+ public IEnumerable<NamespaceDeclaration> GetNamespacePrefixes ()
+ {
+ foreach (var p in source.GetNamespacesInScope (XmlNamespaceScope.All))
+ yield return new NamespaceDeclaration (p.Value, p.Key);
+ }
+ }
}
}
+2010-04-16 Atsushi Enomoto <atsushi@ximian.com>
+
+ * XamlXmlReaderTest.cs : add more detailed read tests, and more
+ file-based tests (not working yet).
+
2010-04-15 Atsushi Enomoto <atsushi@ximian.com>
* XamlTypeTest.cs, XamlLanguageTest.cs : enable AllowedContentTypes
LoadTest ("List_Int32.xml", typeof (List<int>));
}
+ [Test]
+ [Category ("NotWorking")]
+ public void Read_DictionaryInt32String ()
+ {
+ ReadTest ("Dictionary_Int32_String.xml");
+ LoadTest ("Dictionary_Int32_String.xml", typeof (Dictionary<int,string>));
+ }
+
+ [Test]
+ [Category ("NotWorking")]
+ public void Read_DictionaryStringType ()
+ {
+ ReadTest ("Dictionary_String_Type.xml");
+ LoadTest ("Dictionary_String_Type.xml", typeof (Dictionary<string,Type>));
+ }
+
[Test]
public void Read1 ()
{
Assert.AreEqual (XamlNodeType.EndObject, r.NodeType, "eo#2");
Assert.IsFalse (r.Read (), "end");
}
+
+ [Test]
+ public void Read3 ()
+ {
+ var r = GetReader ("Type.xml");
+
+ Assert.IsTrue (r.Read (), "ns#1");
+ Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "ns#2");
+ Assert.AreEqual (XamlLanguage.Xaml2006Namespace, r.Namespace.Namespace, "ns#3");
+
+ Assert.IsTrue (r.Read (), "so#1");
+ Assert.AreEqual (XamlNodeType.StartObject, r.NodeType, "so#2");
+ Assert.AreEqual (XamlLanguage.Type, r.Type, "so#3");
+
+ Assert.IsTrue (r.Read (), "sbase#1");
+ Assert.AreEqual (XamlNodeType.StartMember, r.NodeType, "sbase#2");
+ Assert.AreEqual (XamlLanguage.Base, r.Member, "sbase#3");
+
+ Assert.IsTrue (r.Read (), "vbase#1");
+ Assert.AreEqual (XamlNodeType.Value, r.NodeType, "vbase#2");
+ Assert.IsTrue (r.Value is string, "vbase#3");
+
+ Assert.IsTrue (r.Read (), "ebase#1");
+ Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "ebase#2");
+
+ Assert.IsTrue (r.Read (), "sinit#1");
+ Assert.AreEqual (XamlNodeType.StartMember, r.NodeType, "sinit#2");
+ // FIXME: fix XamlMember.Equals()
+ //Assert.AreEqual (XamlLanguage.Type.GetMember ("Type"), r.Member, "sinit#3");
+ Assert.AreEqual (XamlLanguage.Type.GetMember ("Type").ToString (), r.Member.ToString (), "sinit#3");
+
+ Assert.IsTrue (r.Read (), "vinit#1");
+ Assert.AreEqual (XamlNodeType.Value, r.NodeType, "vinit#2");
+ Assert.AreEqual ("x:Int32", r.Value, "vinit#3"); // string
+
+ Assert.IsTrue (r.Read (), "einit#1");
+ Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "einit#2");
+
+ Assert.IsTrue (r.Read (), "eo#1");
+ Assert.AreEqual (XamlNodeType.EndObject, r.NodeType, "eo#2");
+
+ Assert.IsFalse (r.Read (), "end");
+ }
+
+ [Test]
+ [Category ("NotWorking")]
+ public void Read4 ()
+ {
+ var r = GetReader ("List_Int32.xml");
+
+ Assert.IsTrue (r.Read (), "ns#1");
+ Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "ns#2");
+ Assert.AreEqual ("clr-namespace:System.Collections.Generic;assembly=mscorlib", r.Namespace.Namespace, "ns#3");
+ Assert.AreEqual (String.Empty, r.Namespace.Prefix, "ns#4");
+
+ Assert.IsTrue (r.Read (), "ns2#1");
+ Assert.AreEqual (XamlNodeType.NamespaceDeclaration, r.NodeType, "ns2#2");
+ Assert.AreEqual (XamlLanguage.Xaml2006Namespace, r.Namespace.Namespace, "ns2#3");
+ Assert.AreEqual ("x", r.Namespace.Prefix, "ns2#4");
+
+ Assert.IsTrue (r.Read (), "so#1");
+ Assert.AreEqual (XamlNodeType.StartObject, r.NodeType, "so#2");
+ var xt = new XamlType (typeof (List<int>), r.SchemaContext);
+ Assert.AreEqual (xt, r.Type, "so#3");
+
+ Assert.IsTrue (r.Read (), "sbase#1");
+ Assert.AreEqual (XamlNodeType.StartMember, r.NodeType, "sbase#2");
+ Assert.AreEqual (XamlLanguage.Base, r.Member, "sbase#3");
+
+ Assert.IsTrue (r.Read (), "vbase#1");
+ Assert.AreEqual (XamlNodeType.Value, r.NodeType, "vbase#2");
+ Assert.IsTrue (r.Value is string, "vbase#3");
+
+ Assert.IsTrue (r.Read (), "ebase#1");
+ Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "ebase#2");
+
+ Assert.IsTrue (r.Read (), "scap#1");
+ Assert.AreEqual (XamlNodeType.StartMember, r.NodeType, "scap#2");
+ Assert.AreEqual (xt.GetMember ("Capacity"), r.Member, "scap#3");
+
+ Assert.IsTrue (r.Read (), "vcap#1");
+ Assert.AreEqual (XamlNodeType.Value, r.NodeType, "vcap#2");
+ Assert.AreEqual ("5", r.Value, "vcap#3"); // string
+
+ Assert.IsTrue (r.Read (), "ecap#1");
+ Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "ecap#2");
+
+ Assert.IsTrue (r.Read (), "sItems#1");
+ Assert.AreEqual (XamlNodeType.StartMember, r.NodeType, "sItems#2");
+ Assert.AreEqual (XamlLanguage.Items, r.Member, "sItems#3");
+
+ int [] values = {4, -5, 0, 255, int.MaxValue};
+ var ci = new CultureInfo ("en-US");
+
+ for (int i = 0; i < 5; i++) {
+ Assert.IsTrue (r.Read (), "soItem#1." + i);
+ Assert.AreEqual (XamlNodeType.StartObject, r.NodeType, "soItem#2." + i);
+ Assert.AreEqual (XamlLanguage.Int32, r.Type, "soItem#3." + i);
+
+ Assert.IsTrue (r.Read (), "sItem#1." + i);
+ Assert.AreEqual (XamlNodeType.StartMember, r.NodeType, "sItem#2." + i);
+ Assert.AreEqual (XamlLanguage.Initialization, r.Member, "sItem#3." + i);
+
+ Assert.IsTrue (r.Read (), "vItem#1." + i);
+ Assert.AreEqual (XamlNodeType.Value, r.NodeType, "vItem#2." + i);
+ Assert.AreEqual (values [i].ToString (ci), r.Value, "vItem#3." + i);
+
+ Assert.IsTrue (r.Read (), "eItem#1." + i);
+ Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "eItem#2." + i);
+
+ Assert.IsTrue (r.Read (), "eoItem#1");
+ Assert.AreEqual (XamlNodeType.EndObject, r.NodeType, "eoItem#2");
+ }
+
+ Assert.IsTrue (r.Read (), "eItems#1");
+ Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "eItems#2");
+
+ Assert.IsTrue (r.Read (), "eo#1");
+ Assert.AreEqual (XamlNodeType.EndObject, r.NodeType, "eo#2");
+
+ Assert.IsFalse (r.Read (), "end");
+ }
}
}
+2010-04-16 Atsushi Enomoto <atsushi@ximian.com>
+
+ * Dictionary_Int32_String.xml, Dictionary_String_Type.xml :
+ add more test files (not working though).
+
2010-04-15 Atsushi Enomoto <atsushi@ximian.com>
* DateTime.xml : new test file. (not working though)
--- /dev/null
+<Dictionary x:TypeArguments="x:Int32, x:String" xmlns="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+ <x:String x:Key="0">foo</x:String>
+ <x:String x:Key="5">bar</x:String>
+ <x:String x:Key="-2">baz</x:String>
+</Dictionary>
\ No newline at end of file
--- /dev/null
+<Dictionary x:TypeArguments="x:String, s:Type" xmlns="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+ <x:Type Type="x:Int32" x:Key="t1" />
+ <x:Type Type="s:Int32[]" x:Key="t2" />
+ <x:Type Type="s:Nullable(x:Int32)" x:Key="t3" />
+ <x:Type Type="List(x:Int32)" x:Key="t4" />
+ <x:Type Type="Dictionary(x:Int32, s:DateTime)" x:Key="t5" />
+ <x:Type Type="List(KeyValuePair(x:Int32, s:DateTime))" x:Key="t6" />
+</Dictionary>
\ No newline at end of file