2003-11-21 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl.Operations / XslAttribute.cs
1 //
2 // XslAttribute.cs
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 //      
8 // (C) 2003 Ben Maurer
9 // (C) 2003 Atsushi Enomoto
10 //
11
12 using System;
13 using System.Collections;
14 using System.Xml;
15 using System.Xml.XPath;
16 using System.Xml.Xsl;
17 using System.IO;
18
19 using QName = System.Xml.XmlQualifiedName;
20
21 namespace Mono.Xml.Xsl.Operations {
22         public class XslAttribute : XslCompiledElement {
23                 XslAvt name, ns;
24                 string calcName, calcNs, calcPrefix;
25                 XmlNamespaceManager nsm;
26                 
27                 XslOperation value;
28                 XPathNavigator nav;
29
30                 public XslAttribute (Compiler c) : base (c) {}
31                 
32                 protected override void Compile (Compiler c)
33                 {
34                         nav = c.Input.Clone ();
35                         
36                         name = c.ParseAvtAttribute ("name");
37                         ns = c.ParseAvtAttribute ("namespace");
38
39                         calcName = XslAvt.AttemptPreCalc (ref name);
40                         
41                         if (calcName != null && ns == null) {
42                                 int colonAt = calcName.IndexOf (':');
43                                 calcPrefix = colonAt < 0 ? String.Empty : calcName.Substring (0, colonAt);
44                                 calcName = colonAt < 0 ? calcName : calcName.Substring (colonAt + 1, calcName.Length - colonAt - 1);
45                                 calcNs = nav.GetNamespace (calcPrefix);
46                         } else if (ns != null)
47                                 calcNs = XslAvt.AttemptPreCalc (ref ns);
48                         
49                         if (ns == null && calcNs == null)
50                                 nsm = c.GetNsm ();
51                                 
52                         if (c.Input.MoveToFirstChild ()) {
53                                 value = c.CompileTemplateContent ();
54                                 c.Input.MoveToParent ();
55                         }
56
57                 }
58
59                 public override void Evaluate (XslTransformProcessor p)
60                 {
61                         string nm, nmsp, localName, prefix;
62                         
63                         nm = calcName != null ? calcName : name.Evaluate (p);
64                         nmsp = calcNs != null ? calcNs : ns != null ? ns.Evaluate (p) : String.Empty;
65                         prefix = calcPrefix != null ? calcPrefix : String.Empty;
66
67                         if (nm == "xmlns")
68                                 // It is an error. We must recover by not emmiting any attributes 
69                                 // (unless we throw an exception).
70                                 return;
71
72                         int colonAt = nm.IndexOf (':');
73                         // local attribute
74                         prefix = colonAt < 0 ? String.Empty : nm.Substring (0, colonAt);
75                         nm = colonAt < 0 ? nm : nm.Substring (colonAt + 1, nm.Length - colonAt - 1);
76                         if (colonAt > 0) {
77                                 // global attribute
78                                 if (nmsp == null) {
79                                         QName q = XslNameUtil.FromString (nm, nsm);
80                                         nm = q.Name;
81                                         nmsp = q.Namespace;
82                                 } else
83                                         nm = XslNameUtil.LocalNameOf (nm);
84                         }
85
86                         if (nmsp != String.Empty && prefix == String.Empty) {
87                                 if (nav.MoveToFirstNamespace (XPathNamespaceScope.ExcludeXml)) {
88                                         do {
89                                                 if (nav.Value == nmsp) {
90                                                         prefix = nav.Name;
91                                                         break;
92                                                 }
93                                         } while (nav.MoveToNextNamespace (XPathNamespaceScope.ExcludeXml));
94                                         nav.MoveToParent ();
95                                 }
96                         }
97
98                         if (prefix == "xmlns")
99                                 prefix = String.Empty;  // Should not be allowed.
100
101                         XmlConvert.VerifyName (nm);
102
103                         if (value == null)
104                                 p.Out.WriteAttributeString(prefix, nm, nmsp, "");
105                         else {
106                                 StringWriter sw = new StringWriter ();
107                                 Outputter outputter = new TextOutputter (sw, true);
108                                 p.PushOutput (outputter);
109                                 value.Evaluate (p);                         
110                                 p.PopOutput ();
111                                 outputter.Done ();                              
112                                 p.Out.WriteAttributeString (prefix, nm, nmsp, sw.ToString ());                                                                  
113                         }                                               
114                 }
115         }
116 }