5 // Ben Maurer (bmaurer@users.sourceforge.net)
6 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
9 // (C) 2003 Atsushi Enomoto
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System
.Collections
;
35 using System
.Globalization
;
37 using System
.Xml
.XPath
;
39 using Mono
.Xml
.Xsl
.Operations
;
42 using QName
= System
.Xml
.XmlQualifiedName
;
44 namespace Mono
.Xml
.Xsl
{
45 internal class XslModedTemplateTable
{
47 class TemplateWithPriority
: IComparable
{
48 public readonly double Priority
;
49 public readonly XslTemplate Template
;
50 public readonly Pattern Pattern
;
51 public readonly int TemplateID
;
53 public TemplateWithPriority (XslTemplate t
, Pattern p
)
57 Priority
= p
.DefaultPriority
;
61 public TemplateWithPriority (XslTemplate t
, double p
)
69 public int CompareTo (object o
)
71 TemplateWithPriority a
= this,
72 b
= (TemplateWithPriority
)o
;
74 //Debug.WriteLine (a.Pattern.ToString () + " ? " + b.Pattern.ToString ());
75 //Debug.WriteLine (a.Priority + " " + b.Priority);
77 int r0
= a
.Priority
.CompareTo (b
.Priority
);
78 //Debug.WriteLine (r0);
79 if (r0
!= 0) return r0
;
81 int r1
= a
.TemplateID
.CompareTo (b
.TemplateID
);
82 //Debug.WriteLine (r1);
86 public bool Matches (XPathNavigator n
, XslTransformProcessor p
)
88 //Debug.WriteLine (Pattern.ToString ());
89 return p
.Matches (Pattern
, n
);
93 // [QName name]=>XslTemplate
95 ArrayList unnamedTemplates
= new ArrayList ();
97 XmlQualifiedName mode
;
99 public XslModedTemplateTable (XmlQualifiedName mode
)
102 throw new InvalidOperationException ();
106 public XmlQualifiedName Mode
{
110 public void Add (XslTemplate t
)
112 if (!double.IsNaN (t
.Priority
))
113 unnamedTemplates
.Add (new TemplateWithPriority (t
, t
.Priority
));
118 public void Add (XslTemplate t
, Pattern p
)
120 if (p
is UnionPattern
) {
121 Add (t
, ((UnionPattern
)p
).p0
);
122 Add (t
, ((UnionPattern
)p
).p1
);
126 unnamedTemplates
.Add (new TemplateWithPriority (t
, p
));
131 public XslTemplate
FindMatch (XPathNavigator node
, XslTransformProcessor p
)
133 //Debug.WriteLine ("...");
135 unnamedTemplates
.Sort ();
136 unnamedTemplates
.Reverse ();
141 for (int i
= 0; i
< unnamedTemplates
.Count
; i
++) {
142 TemplateWithPriority t
= (TemplateWithPriority
) unnamedTemplates
[i
];
143 if (t
.Matches (node
, p
))
151 internal class XslTemplateTable
{
152 // [QName mode]=>XslTemplateTable
153 Hashtable templateTables
= new Hashtable ();
154 Hashtable namedTemplates
= new Hashtable ();
155 XslStylesheet parent
;
157 public XslTemplateTable (XslStylesheet parent
)
159 this.parent
= parent
;
162 public Hashtable TemplateTables
{
163 get { return templateTables; }
166 public XslModedTemplateTable
this [XmlQualifiedName mode
] {
168 return templateTables
[mode
] as XslModedTemplateTable
;
172 public void Add (XslTemplate template
)
174 if (template
.Name
!= XmlQualifiedName
.Empty
) {
175 if (namedTemplates
[template
.Name
] != null)
176 throw new InvalidOperationException ("Named template " + template
.Name
+ " is already registered.");
178 namedTemplates
[template
.Name
] = template
;
181 if (template
.Match
== null) return;
183 XslModedTemplateTable tbl
= this [template
.Mode
];
185 tbl
= new XslModedTemplateTable (template
.Mode
);
192 public void Add (XslModedTemplateTable table
)
194 if (this [table
.Mode
] != null)
195 throw new InvalidOperationException ("Mode " + table
.Mode
+ " is already registered.");
196 templateTables
.Add (table
.Mode
, table
);
199 public XslTemplate
FindMatch (XPathNavigator node
, XmlQualifiedName mode
, XslTransformProcessor p
)
203 if (this [mode
] != null)
205 ret
= this [mode
].FindMatch (node
, p
);
206 if (ret
!= null) return ret
;
209 for (int i
= parent
.Imports
.Count
- 1; i
>= 0; i
--)
211 XslStylesheet s
= (XslStylesheet
)parent
.Imports
[i
];
212 ret
= s
.Templates
.FindMatch (node
, mode
, p
);
220 public XslTemplate
FindTemplate (XmlQualifiedName name
)
222 XslTemplate ret
= (XslTemplate
)namedTemplates
[name
];
224 if (ret
!= null) return ret
;
226 for (int i
= parent
.Imports
.Count
- 1; i
>= 0; i
--) {
227 XslStylesheet s
= (XslStylesheet
)parent
.Imports
[i
];
228 ret
= s
.Templates
.FindTemplate (name
);
237 internal class XslTemplate
239 XmlQualifiedName name
;
241 XmlQualifiedName mode
;
242 double priority
= double.NaN
;
243 ArrayList parameters
;
244 XslOperation content
;
246 static int nextId
= 0;
247 public readonly int Id
= nextId
++;
253 public XslTemplate (Compiler c
)
255 if (c
== null) return; // built in template
256 this.style
= c
.CurrentStylesheet
;
260 if (c
.Input
.NamespaceURI
!= Compiler
.XsltNamespace
) {
261 this.name
= QName
.Empty
;
263 this.mode
= QName
.Empty
;
265 this.name
= c
.ParseQNameAttribute ("name");
266 this.match
= c
.CompilePattern (c
.GetAttribute ("match"), c
.Input
);
267 this.mode
= c
.ParseQNameAttribute ("mode");
269 string pri
= c
.GetAttribute ("priority");
272 this.priority
= double.Parse (pri
, CultureInfo
.InvariantCulture
);
273 } catch (FormatException ex
) {
274 throw new XsltException ("Invalid priority number format.", ex
, c
.Input
);
280 stackSize
= c
.PopScope ().VariableHighTide
;
284 public XmlQualifiedName Name
{
288 public Pattern Match
{
294 public XmlQualifiedName Mode
{
298 public double Priority
{
299 get { return priority; }
302 public XslStylesheet Parent
{
303 get { return style; }
306 private void Parse (Compiler c
) {
307 if (c
.Input
.MoveToFirstChild ()) {
310 if (c
.Input
.NodeType
== XPathNodeType
.Text
)
311 { alldone = false; break; }
313 if (c
.Input
.NodeType
!= XPathNodeType
.Element
)
315 if (c
.Input
.NamespaceURI
!= Compiler
.XsltNamespace
)
316 { alldone = false; break; }
317 if (c
.Input
.LocalName
!= "param")
318 { alldone = false; break; }
320 if (this.parameters
== null)
321 this.parameters
= new ArrayList ();
323 parameters
.Add (new XslLocalParam (c
));
325 } while (c
.Input
.MoveToNext ());
327 content
= c
.CompileTemplateContent ();
328 c
.Input
.MoveToParent ();
332 public virtual void Evaluate (XslTransformProcessor p
, Hashtable withParams
)
334 p
.PushStack (stackSize
);
336 if (parameters
!= null) {
337 if (withParams
== null) {
338 int len
= parameters
.Count
;
339 for (int i
= 0; i
< len
; i
++) {
340 XslLocalParam param
= (XslLocalParam
)parameters
[i
];
344 int len
= parameters
.Count
;
345 for (int i
= 0; i
< len
; i
++) {
346 XslLocalParam param
= (XslLocalParam
)parameters
[i
];
347 object o
= withParams
[param
.Name
];
349 param
.Override (p
, o
);
357 content
.Evaluate (p
);
361 public void Evaluate (XslTransformProcessor p
)
367 internal class XslDefaultNodeTemplate
: XslTemplate
{
370 static XslDefaultNodeTemplate instance
= new XslDefaultNodeTemplate (QName
.Empty
);
371 public XslDefaultNodeTemplate (QName mode
) : base (null)
376 public static XslTemplate Instance
{
377 get { return instance; }
380 public override void Evaluate (XslTransformProcessor p
, Hashtable withParams
)
382 p
.ApplyTemplates (p
.CurrentNode
.SelectChildren (XPathNodeType
.All
), mode
, null);
386 internal class XslEmptyTemplate
: XslTemplate
{
388 static XslEmptyTemplate instance
= new XslEmptyTemplate ();
389 XslEmptyTemplate () : base (null) {}
391 public static XslTemplate Instance
{
392 get { return instance; }
395 public override void Evaluate (XslTransformProcessor p
, Hashtable withParams
)
400 internal class XslDefaultTextTemplate
: XslTemplate
{
402 static XslDefaultTextTemplate instance
= new XslDefaultTextTemplate ();
403 XslDefaultTextTemplate () : base (null) {}
405 public static XslTemplate Instance
{
406 get { return instance; }
409 public override void Evaluate (XslTransformProcessor p
, Hashtable withParams
)
411 if (p
.CurrentNode
.NodeType
== XPathNodeType
.Whitespace
) {
412 if (p
.PreserveWhitespace ())
413 p
.Out
.WriteWhitespace (p
.CurrentNode
.Value
);
416 p
.Out
.WriteString (p
.CurrentNode
.Value
);