[NUI][XamlBuild] Fix build error when calling ExitXaml() if XamlOptimization set...
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.XamlBuild / src / public / XamlBuild / XamlGenerator.cs
1 /*
2  * Copyright(c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 using System;
18 using System.CodeDom;
19 using System.CodeDom.Compiler;
20 using System.Collections.Generic;
21 using System.IO;
22 using System.Linq;
23 using System.Reflection;
24 using System.Xml;
25 using Microsoft.Build.Framework;
26 using Microsoft.Build.Utilities;
27 using Microsoft.CSharp;
28 using Mono.Cecil;
29 using Tizen.NUI.Binding;
30 using Tizen.NUI.Xaml;
31
32 namespace Tizen.NUI.Xaml.Build.Tasks
33 {
34     class XamlGenerator
35     {
36         internal XamlGenerator()
37         {
38         }
39
40         private class XmlnsInfo
41         {
42             public void Add(ModuleDefinition module, string nameSpace, int level)
43             {
44                 foreach (TypeDefinition type in module.Types)
45                 {
46                     if (type.Namespace == nameSpace
47                         &&
48                         type.IsPublic == true
49                         &&
50                         type.IsClass == true)
51                     {
52                         bool needUpdate = false;
53                         if (true == classNameToNameSpace.ContainsKey(type.Name))
54                         {
55                             NameSpaceInfo info = classNameToNameSpace[type.Name];
56
57                             if (level > info.level)
58                             {
59                                 needUpdate = true;
60                             }
61                         }
62                         else
63                         {
64                             needUpdate = true;
65                         }
66                         
67                         if (true == needUpdate)
68                         {
69                             classNameToNameSpace[type.Name] = new NameSpaceInfo(type.Namespace, level);
70                         }
71                     }
72                 }
73             }
74
75             public string GetNameSpace(string nameSpace)
76             {
77                 NameSpaceInfo ret;
78
79                 classNameToNameSpace.TryGetValue(nameSpace, out ret);
80
81                 return ret?.nameSpace;
82             }
83
84             private class NameSpaceInfo
85             {
86                 internal NameSpaceInfo(string nameSpace, int level)
87                 {
88                     this.nameSpace = nameSpace;
89                     this.level = level;
90                 }
91
92                 internal string nameSpace;
93                 internal int level;
94             }
95
96             private Dictionary<string, NameSpaceInfo> classNameToNameSpace = new Dictionary<string, NameSpaceInfo>();
97         }
98
99         static private Dictionary<string, XmlnsInfo> xmlnsNameToInfo = new Dictionary<string, XmlnsInfo>();
100
101         internal string ReferencePath
102         {
103             set
104             {
105                 if (!string.IsNullOrEmpty(value))
106                 {
107                     List<ModuleDefinition> assemblyList = new List<ModuleDefinition>();
108
109                     var paths = value.Replace("//", "/").Split(';');
110                     foreach (var p in paths)
111                     {
112                         ModuleDefinition module = ModuleDefinition.ReadModule(p);
113
114                         foreach (var attr in module.Assembly.CustomAttributes)
115                         {
116                             if (attr.AttributeType.FullName == "Tizen.NUI.XmlnsDefinitionAttribute")
117                             {
118                                 string xmlNamespace = attr.ConstructorArguments[0].Value as string;
119                                 string clrNamespace = attr.ConstructorArguments[1].Value as string;
120
121                                 int level = 0;
122                                 string assemblyName = module.Assembly.FullName;
123
124                                 if (true == attr.HasProperties)
125                                 {
126                                     foreach (var property in attr.Properties)
127                                     {
128                                         if ("Level" == property.Name)
129                                         {
130                                             level = int.Parse(property.Argument.Value.ToString());
131                                         }
132                                         if ("AssemblyName" == property.Name)
133                                         {
134                                             assemblyName = property.Argument.Value as string;
135                                         }
136                                     }
137                                 }
138
139                                 XmlnsInfo xmlsInfo = null;
140
141                                 if (xmlnsNameToInfo.ContainsKey(xmlNamespace))
142                                 {
143                                     xmlsInfo = xmlnsNameToInfo[xmlNamespace];
144                                 }
145                                 else
146                                 {
147                                     xmlsInfo = new XmlnsInfo();
148                                     xmlnsNameToInfo.Add(xmlNamespace, xmlsInfo);
149                                 }
150
151                                 xmlsInfo.Add(module, clrNamespace, level);
152                             }
153                         }
154                     }
155                 }
156             }
157         }
158
159         public XamlGenerator(
160             ITaskItem taskItem,
161             string language,
162             string assemblyName,
163             string outputFile,
164             string ReferencePath,
165             TaskLoggingHelper logger)
166             : this(
167                 taskItem.ItemSpec,
168                 language,
169                 taskItem.GetMetadata("ManifestResourceName"),
170                 taskItem.GetMetadata("TargetPath"),
171                 assemblyName,
172                 outputFile,
173                 logger)
174         {
175             this.ReferencePath = ReferencePath;
176         }
177
178         static int generatedTypesCount;
179         internal static CodeDomProvider Provider = new CSharpCodeProvider();
180
181         public string XamlFile { get; }
182         public string Language { get; }
183         public string ResourceId { get; }
184         public string TargetPath { get; }
185         public string AssemblyName { get; }
186         public string OutputFile { get; }
187         public TaskLoggingHelper Logger { get; }
188         public string RootClrNamespace { get; private set; }
189         public string RootType { get; private set; }
190         public bool AddXamlCompilationAttribute { get; set; }
191         public int XamlOptimization { get; set; }
192         bool GenerateDefaultCtor { get; set; }
193         bool HideFromIntellisense { get; set; }
194         bool XamlResourceIdOnly { get; set; }
195         internal IEnumerable<CodeMemberField> NamedFields { get; set; }
196         internal CodeTypeReference BaseType { get; set; }
197         string classModifier { get; set; }
198
199         public XamlGenerator(
200             string xamlFile,
201             string language,
202             string resourceId,
203             string targetPath,
204             string assemblyName,
205             string outputFile,
206             TaskLoggingHelper logger = null)
207         {
208             XamlFile = xamlFile;
209             Language = language;
210             ResourceId = resourceId;
211             TargetPath = targetPath;
212             AssemblyName = assemblyName;
213             OutputFile = outputFile;
214             Logger = logger;
215         }
216
217         //returns true if a file is generated
218         public bool Execute()
219         {
220             Logger?.LogMessage(MessageImportance.Low, "Source: {0}", XamlFile);
221             Logger?.LogMessage(MessageImportance.Low, " Language: {0}", Language);
222             Logger?.LogMessage(MessageImportance.Low, " ResourceID: {0}", ResourceId);
223             Logger?.LogMessage(MessageImportance.Low, " TargetPath: {0}", TargetPath);
224             Logger?.LogMessage(MessageImportance.Low, " AssemblyName: {0}", AssemblyName);
225             Logger?.LogMessage(MessageImportance.Low, " OutputFile {0}", OutputFile);
226
227             using (StreamReader reader = File.OpenText(XamlFile))
228                 if (!ParseXaml(reader))
229                     return false;
230
231             GenerateCode(OutputFile);
232
233             return true;
234         }
235
236         internal bool ParseXaml(TextReader xaml)
237         {
238             var xmlDoc = new XmlDocument();
239             xmlDoc.Load(xaml);
240
241             // if the following xml processing instruction is present
242             //
243             // <?xaml-comp compile="true" ?>
244             //
245             // we will generate a xaml.g.cs file with the default ctor calling InitializeComponent, and a XamlCompilation attribute
246             var hasXamlCompilationProcessingInstruction = GetXamlCompilationProcessingInstruction(xmlDoc);
247
248             var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
249             nsmgr.AddNamespace("__f__", XamlParser.XFUri);
250
251             var root = xmlDoc.SelectSingleNode("/*", nsmgr);
252             if (root == null) {
253                 Logger?.LogMessage(MessageImportance.Low, " No root node found");
254                 return false;
255             }
256
257             foreach (XmlAttribute attr in root.Attributes) {
258                 if (attr.Name == "xmlns")
259                     nsmgr.AddNamespace("", attr.Value); //Add default xmlns
260                 if (attr.Prefix != "xmlns")
261                     continue;
262                 nsmgr.AddNamespace(attr.LocalName, attr.Value);
263             }
264
265             var rootClass = root.Attributes["Class", XamlParser.X2006Uri]
266                          ?? root.Attributes["Class", XamlParser.X2009Uri];
267
268             if (rootClass != null) {
269                 string rootType, rootNs, rootAsm, targetPlatform;
270                 XmlnsHelper.ParseXmlns(rootClass.Value, out rootType, out rootNs, out rootAsm, out targetPlatform);
271                 RootType = rootType;
272                 RootClrNamespace = rootNs;
273             }
274             else if (hasXamlCompilationProcessingInstruction) {
275                 RootClrNamespace = "__XamlGeneratedCode__";
276                 RootType = $"__Type{generatedTypesCount++}";
277                 GenerateDefaultCtor = true;
278                 AddXamlCompilationAttribute = true;
279                 HideFromIntellisense = true;
280             }
281             else { // rootClass == null && !hasXamlCompilationProcessingInstruction) {
282                 XamlResourceIdOnly = true; //only generate the XamlResourceId assembly attribute
283                 return true;
284             }
285
286             NamedFields = GetCodeMemberFields(root, nsmgr);
287             var typeArguments = GetAttributeValue(root, "TypeArguments", XamlParser.X2006Uri, XamlParser.X2009Uri);
288             classModifier = GetAttributeValue(root, "ClassModifier", XamlParser.X2006Uri, XamlParser.X2009Uri);
289             var xmlType = new XmlType(root.NamespaceURI, root.LocalName, typeArguments != null ? TypeArgumentsParser.ParseExpression(typeArguments, nsmgr, null) : null);
290             BaseType = GetType(xmlType, root.GetNamespaceOfPrefix);
291
292             return true;
293         }
294
295         static System.Version version = typeof(XamlGenerator).Assembly.GetName().Version;
296         static CodeAttributeDeclaration GeneratedCodeAttrDecl =>
297             new CodeAttributeDeclaration(new CodeTypeReference($"global::{typeof(GeneratedCodeAttribute).FullName}"),
298                         new CodeAttributeArgument(new CodePrimitiveExpression("Tizen.NUI.Xaml.Build.Tasks.XamlG")),
299                         new CodeAttributeArgument(new CodePrimitiveExpression($"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}")));
300
301         void GenerateCode(string outFilePath)
302         {
303             //Create the target directory if required
304             Directory.CreateDirectory(System.IO.Path.GetDirectoryName(outFilePath));
305
306             var ccu = new CodeCompileUnit();
307             ccu.AssemblyCustomAttributes.Add(
308                 new CodeAttributeDeclaration(new CodeTypeReference($"global::{typeof(XamlResourceIdAttribute).FullName}"),
309                                              new CodeAttributeArgument(new CodePrimitiveExpression(ResourceId)),
310                                              new CodeAttributeArgument(new CodePrimitiveExpression(TargetPath.Replace('\\', '/'))), //use forward slashes, paths are uris-like
311                                              new CodeAttributeArgument(RootType == null ? (CodeExpression)new CodePrimitiveExpression(null) : new CodeTypeOfExpression($"global::{RootClrNamespace}.{RootType}"))
312                                             ));
313             if (XamlResourceIdOnly)
314                 goto writeAndExit;
315
316             if (RootType == null)
317                 throw new Exception("Something went wrong while executing XamlG");
318
319             var declNs = new CodeNamespace(RootClrNamespace);
320             ccu.Namespaces.Add(declNs);
321
322             var declType = new CodeTypeDeclaration(RootType) {
323                 IsPartial = true,
324                 TypeAttributes = GetTypeAttributes(classModifier),
325                 CustomAttributes = {
326                     new CodeAttributeDeclaration(new CodeTypeReference(XamlCTask.xamlNameSpace + ".XamlFilePathAttribute"),
327                          new CodeAttributeArgument(new CodePrimitiveExpression(XamlFile))),
328                 }
329             };
330             if (AddXamlCompilationAttribute)
331                 declType.CustomAttributes.Add(
332                     new CodeAttributeDeclaration(new CodeTypeReference(XamlCTask.xamlNameSpace + ".XamlCompilationAttribute"),
333                                                  new CodeAttributeArgument(new CodeSnippetExpression($"global::{typeof(XamlCompilationOptions).FullName}.Compile"))));
334             if (HideFromIntellisense)
335                 declType.CustomAttributes.Add(
336                     new CodeAttributeDeclaration(new CodeTypeReference($"global::{typeof(System.ComponentModel.EditorBrowsableAttribute).FullName}"),
337                                                  new CodeAttributeArgument(new CodeSnippetExpression($"global::{typeof(System.ComponentModel.EditorBrowsableState).FullName}.{nameof(System.ComponentModel.EditorBrowsableState.Never)}"))));
338
339             declType.BaseTypes.Add(BaseType);
340
341             declNs.Types.Add(declType);
342
343             //Create a default ctor calling InitializeComponent
344             if (GenerateDefaultCtor) {
345                 var ctor = new CodeConstructor {
346                     Attributes = MemberAttributes.Public,
347                     CustomAttributes = { GeneratedCodeAttrDecl },
348                     Statements = {
349                         new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "InitializeComponent")
350                     }
351                 };
352
353                 declType.Members.Add(ctor);
354             }
355
356             //Create InitializeComponent()
357             var initcomp = new CodeMemberMethod {
358                 Name = "InitializeComponent",
359                 CustomAttributes = { GeneratedCodeAttrDecl }
360             };
361
362             declType.Members.Add(initcomp);
363
364             //Create and initialize fields
365
366                         if(0 == XamlOptimization)
367                         {
368                 initcomp.Statements.Add(new CodeMethodInvokeExpression(
369                     new CodeTypeReferenceExpression(new CodeTypeReference($"global::{typeof(Extensions).FullName}")),
370                     "LoadFromXaml", new CodeThisReferenceExpression(), new CodeTypeOfExpression(declType.Name)));
371
372                 var exitXamlComp = new CodeMemberMethod()
373                 {
374                     Name = "ExitXaml",
375                     CustomAttributes = { GeneratedCodeAttrDecl },
376                     Attributes = MemberAttributes.Assembly | MemberAttributes.Final
377                 };
378                 declType.Members.Add(exitXamlComp);
379             }
380             else
381                         {
382                 var loadExaml_invoke = new CodeMethodInvokeExpression(
383                     new CodeTypeReferenceExpression(new CodeTypeReference($"global::Tizen.NUI.EXaml.EXamlExtensions")),
384                     "LoadFromEXamlByRelativePath", new CodeThisReferenceExpression(),
385                     new CodeMethodInvokeExpression()
386                     { Method = new CodeMethodReferenceExpression() { MethodName = "GetEXamlPath" } });
387
388                 CodeAssignStatement assignEXamlObject = new CodeAssignStatement(
389                         new CodeVariableReferenceExpression("eXamlData"), loadExaml_invoke);
390
391                 initcomp.Statements.Add(assignEXamlObject);
392                         }
393
394             foreach (var namedField in NamedFields) {
395                 if(namedField.Type.BaseType.Contains("-"))
396                 {
397                     namedField.Type.BaseType = namedField.Type.BaseType.Replace("-", ".");
398                 }
399                 declType.Members.Add(namedField);
400
401                 var find_invoke = new CodeMethodInvokeExpression(
402                     new CodeMethodReferenceExpression(
403                         new CodeTypeReferenceExpression(new CodeTypeReference($"global::Tizen.NUI.Binding.NameScopeExtensions")),
404                         "FindByName", namedField.Type),
405                     new CodeThisReferenceExpression(), new CodePrimitiveExpression(namedField.Name));
406
407                 CodeAssignStatement assign = new CodeAssignStatement(
408                     new CodeVariableReferenceExpression(namedField.Name), find_invoke);
409
410                 initcomp.Statements.Add(assign);
411             }
412
413                         if(0 != XamlOptimization)
414                         {
415                 declType.Members.Add(new CodeMemberField
416                 {
417                     Name = "eXamlData",
418                     Type = new CodeTypeReference("System.Object"),
419                     Attributes = MemberAttributes.Private,
420                     CustomAttributes = { GeneratedCodeAttrDecl }
421                 });
422
423                 var getEXamlPathcomp = new CodeMemberMethod()
424                 {
425                     Name = "GetEXamlPath",
426                     ReturnType = new CodeTypeReference(typeof(string)),
427                     CustomAttributes = { GeneratedCodeAttrDecl }
428                 };
429
430                 getEXamlPathcomp.Statements.Add(new CodeMethodReturnStatement(new CodeDefaultValueExpression(new CodeTypeReference(typeof(string)))));
431
432                 declType.Members.Add(getEXamlPathcomp);
433
434                 GenerateMethodExitXaml(declType);
435                         }
436         writeAndExit:
437             //write the result
438             using (var writer = new StreamWriter(outFilePath))
439                 Provider.GenerateCodeFromCompileUnit(ccu, writer, new CodeGeneratorOptions());
440         }
441
442         private void GenerateMethodExitXaml(CodeTypeDeclaration declType)
443         {
444             var removeEventsComp = new CodeMemberMethod()
445             {
446                 Name = "RemoveEventsInXaml",
447                 CustomAttributes = { GeneratedCodeAttrDecl }
448             };
449
450             removeEventsComp.Statements.Add(new CodeMethodInvokeExpression(
451                 new CodeTypeReferenceExpression(new CodeTypeReference($"global::Tizen.NUI.EXaml.EXamlExtensions")),
452                 "RemoveEventsInXaml", new CodeVariableReferenceExpression("eXamlData")));
453
454             declType.Members.Add(removeEventsComp);
455
456             var exitXamlComp = new CodeMemberMethod()
457             {
458                 Name = "ExitXaml",
459                 CustomAttributes = { GeneratedCodeAttrDecl },
460                 Attributes = MemberAttributes.Assembly | MemberAttributes.Final
461             };
462
463             exitXamlComp.Statements.Add(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression()
464             {
465                 MethodName = "RemoveEventsInXaml",
466             }));
467
468             var disposeXamlElements_invoke = new CodeMethodInvokeExpression(
469                 new CodeTypeReferenceExpression(new CodeTypeReference($"global::Tizen.NUI.EXaml.EXamlExtensions")),
470                 "DisposeXamlElements", new CodeThisReferenceExpression());
471
472             exitXamlComp.Statements.Add(disposeXamlElements_invoke);
473
474             CodeAssignStatement eXamlDataAssign = new CodeAssignStatement(
475                     new CodeVariableReferenceExpression("eXamlData"), new CodeDefaultValueExpression(new CodeTypeReference(typeof(object))));
476
477             exitXamlComp.Statements.Add(eXamlDataAssign);
478
479             foreach (var namedField in NamedFields)
480             {
481                 CodeAssignStatement assign = new CodeAssignStatement(
482                     new CodeVariableReferenceExpression(namedField.Name), new CodeDefaultValueExpression(namedField.Type));
483
484                 exitXamlComp.Statements.Add(assign);
485             }
486
487             declType.Members.Add(exitXamlComp);
488         }
489
490         static System.Reflection.TypeAttributes GetTypeAttributes(string classModifier)
491         {
492             var access = System.Reflection.TypeAttributes.Public;
493             if (classModifier != null)
494             {
495                 switch (classModifier.ToLowerInvariant())
496                 {
497                     default:
498                     case "public":
499                         access = System.Reflection.TypeAttributes.Public;
500                         break;
501                     case "internal":
502                     case "notpublic": //WPF syntax
503                         access = System.Reflection.TypeAttributes.NotPublic;
504                         break;
505                 }
506             }
507             return access;
508         }
509
510         static IEnumerable<CodeMemberField> GetCodeMemberFields(XmlNode root, XmlNamespaceManager nsmgr)
511         {
512             var xPrefix = nsmgr.LookupPrefix(XamlParser.X2006Uri) ?? nsmgr.LookupPrefix(XamlParser.X2009Uri);
513             if (xPrefix == null)
514                 yield break;
515
516             XmlNodeList names =
517                 root.SelectNodes(
518                     "//*[@" + xPrefix + ":Name" +
519                     "][not(ancestor:: __f__:DataTemplate) and not(ancestor:: __f__:ControlTemplate) and not(ancestor:: __f__:Style) and not(ancestor:: __f__:VisualStateManager.VisualStateGroups)]", nsmgr);
520             foreach (XmlNode node in names) {
521                 var name = GetAttributeValue(node, "Name", XamlParser.X2006Uri, XamlParser.X2009Uri);
522                 var typeArguments = GetAttributeValue(node, "TypeArguments", XamlParser.X2006Uri, XamlParser.X2009Uri);
523                 var fieldModifier = GetAttributeValue(node, "FieldModifier", XamlParser.X2006Uri, XamlParser.X2009Uri);
524
525                 var xmlType = new XmlType(node.NamespaceURI, node.LocalName,
526                                           typeArguments != null
527                                           ? TypeArgumentsParser.ParseExpression(typeArguments, nsmgr, null)
528                                           : null);
529
530                 var access = MemberAttributes.Public;
531                 if (fieldModifier != null) {
532                     switch (fieldModifier.ToLowerInvariant()) {
533                         default:
534                         case "private":
535                             access = MemberAttributes.Private;
536                             break;
537                         case "public":
538                             access = MemberAttributes.Public;
539                             break;
540                         case "protected":
541                             access = MemberAttributes.Family;
542                             break;
543                         case "internal":
544                         case "notpublic": //WPF syntax
545                             access = MemberAttributes.Assembly;
546                             break;
547                     }
548                 }
549
550                 yield return new CodeMemberField {
551                     Name = name,
552                     Type = GetType(xmlType, node.GetNamespaceOfPrefix),
553                     Attributes = access,
554                     CustomAttributes = { GeneratedCodeAttrDecl }
555                 };
556             }
557         }
558
559         static bool GetXamlCompilationProcessingInstruction(XmlDocument xmlDoc)
560         {
561             var instruction = xmlDoc.SelectSingleNode("processing-instruction('xaml-comp')") as XmlProcessingInstruction;
562             if (instruction == null)
563                 return false;
564
565             var parts = instruction.Data.Split(' ', '=');
566             string compileValue = null;
567             var indexOfCompile = Array.IndexOf(parts, "compile");
568             if (indexOfCompile != -1)
569                 compileValue = parts[indexOfCompile + 1].Trim('"', '\'');
570             return compileValue.Equals("true", StringComparison.InvariantCultureIgnoreCase);
571         }
572
573         static CodeTypeReference GetType(XmlType xmlType,
574             Func<string, string> getNamespaceOfPrefix = null)
575         {
576             var type = xmlType.Name;
577             if (type.Contains("-"))
578             {
579                 type = type.Replace('-', '.');
580             }
581             var ns = GetClrNamespace(xmlType.NamespaceUri, xmlType.Name);
582             if (ns != null)
583                 type = $"{ns}.{type}";
584
585             if (xmlType.TypeArguments != null)
586                 type = $"{type}`{xmlType.TypeArguments.Count}";
587
588             var returnType = new CodeTypeReference(type);
589             if (ns != null)
590                 returnType.Options |= CodeTypeReferenceOptions.GlobalReference;
591
592             if (xmlType.TypeArguments != null)
593                 foreach (var typeArg in xmlType.TypeArguments)
594                     returnType.TypeArguments.Add(GetType(typeArg, getNamespaceOfPrefix));
595
596             return returnType;
597         }
598
599         static string GetClrNamespace(string namespaceuri, string className)
600         {
601             XmlnsInfo xmlnsInfo = null;
602
603             xmlnsNameToInfo.TryGetValue(namespaceuri, out xmlnsInfo);
604
605             if (null != xmlnsInfo)
606             {
607                 string nameSpace = xmlnsInfo.GetNameSpace(className);
608
609                 if (null != nameSpace)
610                 {
611                     return nameSpace;
612                 }
613             }
614
615             if (namespaceuri == "http://tizen.org/Tizen.NUI/2018/XAML")
616                 return "Tizen.NUI.Xaml";
617             if (namespaceuri == XamlParser.XFUri)
618                 return "Tizen.NUI.Xaml";
619             if (namespaceuri == XamlParser.X2009Uri)
620                 return "System";
621             //if (namespaceuri != XamlParser.X2006Uri && !namespaceuri.StartsWith("clr-namespace", StringComparison.InvariantCulture) && !namespaceuri.StartsWith("using", StringComparison.InvariantCulture))
622             //    throw new Exception($"Can't load types from xmlns {namespaceuri}");
623             return XmlnsHelper.ParseNamespaceFromXmlns(namespaceuri);
624         }
625
626         static string GetAttributeValue(XmlNode node, string localName, params string[] namespaceURIs)
627         {
628             if (node == null)
629                 throw new ArgumentNullException(nameof(node));
630             if (localName == null)
631                 throw new ArgumentNullException(nameof(localName));
632             if (namespaceURIs == null)
633                 throw new ArgumentNullException(nameof(namespaceURIs));
634             foreach (var namespaceURI in namespaceURIs) {
635                 var attr = node.Attributes[localName, namespaceURI];
636                 if (attr == null)
637                     continue;
638                 return attr.Value;
639             }
640             return null;
641         }
642     }
643 }
644