From 054ecf2704ac5d736ffb97c2932e1e078041008a Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Thu, 17 Nov 2016 20:31:05 +0100 Subject: [Xaml] cleanup xmlns usage, add XmlnsDefinition (#531) * [Xaml] cleanup xmlns usage, add XmlnsDefinition * docs --- Xamarin.Forms.Xaml/Properties/AssemblyInfo.cs | 11 ++++- Xamarin.Forms.Xaml/TypeArgumentsParser.cs | 18 +++++++- Xamarin.Forms.Xaml/XamlParser.cs | 64 ++++++++++++++++++--------- Xamarin.Forms.Xaml/XamlServiceProvider.cs | 2 +- Xamarin.Forms.Xaml/XmlnsHelper.cs | 13 +----- 5 files changed, 70 insertions(+), 38 deletions(-) (limited to 'Xamarin.Forms.Xaml') diff --git a/Xamarin.Forms.Xaml/Properties/AssemblyInfo.cs b/Xamarin.Forms.Xaml/Properties/AssemblyInfo.cs index 58c48d26..d6b8ae9c 100644 --- a/Xamarin.Forms.Xaml/Properties/AssemblyInfo.cs +++ b/Xamarin.Forms.Xaml/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Runtime.CompilerServices; +using Xamarin.Forms; using Xamarin.Forms.Internals; // Information about this assembly is defined by the following attributes. @@ -23,4 +24,12 @@ using Xamarin.Forms.Internals; [assembly: InternalsVisibleTo("Xamarin.Forms.Xaml.UnitTests")] [assembly: InternalsVisibleTo("Xamarin.Forms.Build.Tasks")] [assembly: InternalsVisibleTo("Xamarin.Forms.Xaml.Design")] -[assembly: Preserve] \ No newline at end of file +[assembly: Preserve] + +[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms.Xaml")] +[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml", "Xamarin.Forms.Xaml")] +[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml", "System", AssemblyName = "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] +[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml", "System", AssemblyName = "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] +[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2009/xaml", "Xamarin.Forms.Xaml")] +[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2009/xaml", "System", AssemblyName = "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] +[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2009/xaml", "System", AssemblyName = "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] \ No newline at end of file diff --git a/Xamarin.Forms.Xaml/TypeArgumentsParser.cs b/Xamarin.Forms.Xaml/TypeArgumentsParser.cs index 59b2dd0a..525b4d74 100644 --- a/Xamarin.Forms.Xaml/TypeArgumentsParser.cs +++ b/Xamarin.Forms.Xaml/TypeArgumentsParser.cs @@ -47,8 +47,22 @@ namespace Xamarin.Forms.Xaml type.Substring(type.IndexOf('(') + 1, type.LastIndexOf(')') - type.IndexOf('(') - 1), resolver, lineinfo); type = type.Substring(0, type.IndexOf('(')); } - var namespaceuri = type.Contains(":") ? resolver.LookupNamespace(type.Split(':')[0].Trim()) : ""; - return new XmlType(namespaceuri, type, typeArguments); + + var split = type.Split(':'); + if (split.Length > 2) + return null; + + string prefix, name; + if (split.Length == 2) { + prefix = split [0]; + name = split [1]; + } else { + prefix = ""; + name = split [0]; + } + + var namespaceuri = resolver.LookupNamespace(prefix); + return new XmlType(namespaceuri, name, typeArguments); } } } \ No newline at end of file diff --git a/Xamarin.Forms.Xaml/XamlParser.cs b/Xamarin.Forms.Xaml/XamlParser.cs index f2ac3197..9e841b9f 100644 --- a/Xamarin.Forms.Xaml/XamlParser.cs +++ b/Xamarin.Forms.Xaml/XamlParser.cs @@ -34,7 +34,7 @@ using System.Xml; namespace Xamarin.Forms.Xaml { - internal static class XamlParser + static class XamlParser { public static void ParseXaml(RootNode rootNode, XmlReader reader) { @@ -83,16 +83,16 @@ namespace Xamarin.Forms.Xaml var prop = ReadNode(reader); if (prop != null) node.Properties.Add(XmlName.xArguments, prop); - // 3. DataTemplate (should be handled by 4.) } + // 3. DataTemplate (should be handled by 4.) else if (node.XmlType.NamespaceUri == "http://xamarin.com/schemas/2014/forms" && (node.XmlType.Name == "DataTemplate" || node.XmlType.Name == "ControlTemplate")) { var prop = ReadNode(reader, true); if (prop != null) node.Properties.Add(XmlName._CreateContent, prop); - // 4. Implicit content, implicit collection, or collection syntax. Add to CollectionItems, resolve case later. } + // 4. Implicit content, implicit collection, or collection syntax. Add to CollectionItems, resolve case later. else { var item = ReadNode(reader, true); @@ -191,7 +191,10 @@ namespace Xamarin.Forms.Xaml continue; } - var propertyName = new XmlName(reader.NamespaceURI, reader.LocalName); + var namespaceUri = reader.NamespaceURI; + if (reader.LocalName.Contains(".") && namespaceUri == "") + namespaceUri = ((IXmlNamespaceResolver)reader).LookupNamespace(""); + var propertyName = new XmlName(namespaceUri, reader.LocalName); object value = reader.Value; @@ -283,39 +286,56 @@ namespace Xamarin.Forms.Xaml ((IXmlLineInfo)reader).LinePosition); } + static IList s_xmlnsDefinitions; + + static void GatherXmlnsDefinitionAttributes() + { + //this could be extended to look for [XmlnsDefinition] in all assemblies + var assemblies = new [] { + typeof(View).GetTypeInfo().Assembly, + typeof(XamlLoader).GetTypeInfo().Assembly, + }; + + s_xmlnsDefinitions = new List(); + + foreach (var assembly in assemblies) + foreach (XmlnsDefinitionAttribute attribute in assembly.GetCustomAttributes(typeof(XmlnsDefinitionAttribute))) { + s_xmlnsDefinitions.Add(attribute); + attribute.AssemblyName = attribute.AssemblyName ?? assembly.FullName; + } + } + public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly, out XamlParseException exception) { + if (s_xmlnsDefinitions == null) + GatherXmlnsDefinitionAttributes(); + var namespaceURI = xmlType.NamespaceUri; var elementName = xmlType.Name; var typeArguments = xmlType.TypeArguments; exception = null; - var lookupAssemblies = new List>(); //namespace, assemblyqualifiednamed + var lookupAssemblies = new List(); var lookupNames = new List(); - if (!XmlnsHelper.IsCustom(namespaceURI)) - { - lookupAssemblies.Add(new Tuple("Xamarin.Forms", typeof (View).GetTypeInfo().Assembly.FullName)); - lookupAssemblies.Add(new Tuple("Xamarin.Forms.Xaml", typeof (XamlLoader).GetTypeInfo().Assembly.FullName)); - } - else if (namespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml" || - namespaceURI == "http://schemas.microsoft.com/winfx/2006/xaml") - { - lookupAssemblies.Add(new Tuple("Xamarin.Forms.Xaml", typeof (XamlLoader).GetTypeInfo().Assembly.FullName)); - lookupAssemblies.Add(new Tuple("System", typeof (object).GetTypeInfo().Assembly.FullName)); //mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - lookupAssemblies.Add(new Tuple("System", typeof (Uri).GetTypeInfo().Assembly.FullName)); //System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + foreach (var xmlnsDef in s_xmlnsDefinitions) { + if (xmlnsDef.XmlNamespace != namespaceURI) + continue; + lookupAssemblies.Add(xmlnsDef); } - else - { + + if (lookupAssemblies.Count == 0) { string ns, asmstring, _; XmlnsHelper.ParseXmlns(namespaceURI, out _, out ns, out asmstring, out _); - lookupAssemblies.Add(new Tuple(ns, asmstring ?? currentAssembly.FullName)); + lookupAssemblies.Add(new XmlnsDefinitionAttribute(namespaceURI, ns) { + AssemblyName = asmstring ?? currentAssembly.FullName + }); } lookupNames.Add(elementName); - if (namespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml") - lookupNames.Add(elementName + "Extension"); + lookupNames.Add(elementName + "Extension"); + for (var i = 0; i < lookupNames.Count; i++) { var name = lookupNames[i]; @@ -329,7 +349,7 @@ namespace Xamarin.Forms.Xaml Type type = null; foreach (var asm in lookupAssemblies) { foreach (var name in lookupNames) - if ((type = Type.GetType($"{asm.Item1}.{name}, {asm.Item2}")) != null) + if ((type = Type.GetType($"{asm.ClrNamespace}.{name}, {asm.AssemblyName}")) != null) break; if (type != null) break; diff --git a/Xamarin.Forms.Xaml/XamlServiceProvider.cs b/Xamarin.Forms.Xaml/XamlServiceProvider.cs index 5599cbbc..19dd96f5 100644 --- a/Xamarin.Forms.Xaml/XamlServiceProvider.cs +++ b/Xamarin.Forms.Xaml/XamlServiceProvider.cs @@ -231,7 +231,7 @@ namespace Xamarin.Forms.Xaml.Internals xmlLineInfo = lineInfoProvider.XmlLineInfo; } - var namespaceuri = prefix == null ? "" : namespaceResolver.LookupNamespace(prefix); + var namespaceuri = namespaceResolver.LookupNamespace(prefix); if (namespaceuri == null) { exception = new XamlParseException(string.Format("No xmlns declaration for prefix \"{0}\"", prefix), xmlLineInfo); diff --git a/Xamarin.Forms.Xaml/XmlnsHelper.cs b/Xamarin.Forms.Xaml/XmlnsHelper.cs index e3e37de4..e29dbc0c 100644 --- a/Xamarin.Forms.Xaml/XmlnsHelper.cs +++ b/Xamarin.Forms.Xaml/XmlnsHelper.cs @@ -2,19 +2,8 @@ using System; namespace Xamarin.Forms.Xaml { - internal static class XmlnsHelper + static class XmlnsHelper { - public static bool IsCustom(string ns) - { - switch (ns) - { - case "": - case "http://xamarin.com/schemas/2014/forms": - return false; - } - return true; - } - public static string ParseNamespaceFromXmlns(string xmlns) { string typeName; -- cgit v1.2.3