1 //------------------------------------------------------------------------------
2 // <copyright file="XslAst.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
9 using System.Collections.Generic;
10 using System.Collections.ObjectModel;
11 using System.Diagnostics;
12 using System.Globalization;
13 using System.Xml.Xsl.Qil;
15 namespace System.Xml.Xsl.Xslt {
16 using ContextInfo = XsltInput.ContextInfo;
17 using XPathQilFactory = System.Xml.Xsl.XPath.XPathQilFactory;
19 // Set of classes that represent XSLT AST
21 // XSLT AST is a tree of nodes that represent content of xsl template.
22 // All nodes are subclasses of QilNode. This was done to keep NodeCtor and Text ctors
23 // the sames nodes thay will be in resulting QilExpression tree.
24 // So we have: ElementCtor, AttributeCtor, QilTextCtor, CommentCtor, PICtor, NamespaceDecl, List.
25 // Plus couple subclasses of XslNode that represent different xslt instructions
26 // including artifitial: Sort, ExNamespaceDecl, UseAttributeSets
28 internal enum XslNodeType {
63 internal class NsDecl {
64 public readonly NsDecl Prev;
65 public readonly string Prefix; // Empty string denotes the default namespace, null - extension or excluded namespace
66 public readonly string NsUri; // null means "#all" -- all namespace defined above this one are excluded.
68 public NsDecl(NsDecl prev, string prefix, string nsUri) {
69 Debug.Assert(nsUri != null || Prefix == null);
76 internal class XslNode {
77 public readonly XslNodeType NodeType;
78 public ISourceLineInfo SourceLine;
79 public NsDecl Namespaces;
80 public readonly QilName Name; // name or mode
81 public readonly object Arg; // select or test or terminate or stylesheet;-)
82 public readonly XslVersion XslVersion;
83 public XslFlags Flags;
84 private List<XslNode> content;
86 public XslNode(XslNodeType nodeType, QilName name, object arg, XslVersion xslVer) {
87 this.NodeType = nodeType;
90 this.XslVersion = xslVer;
93 public XslNode(XslNodeType nodeType) {
94 this.NodeType = nodeType;
95 this.XslVersion = XslVersion.Current;
98 public string Select { get { return (string)Arg; } }
99 public bool ForwardsCompatible { get { return XslVersion == XslVersion.ForwardsCompatible; } }
101 // -------------------------------- Content Management --------------------------------
103 private static readonly IList<XslNode> EmptyList = new List<XslNode>().AsReadOnly();
105 public IList<XslNode> Content {
106 get { return content ?? EmptyList; }
109 public void SetContent(List<XslNode> content) {
110 this.content = content;
113 public void AddContent(XslNode node) {
114 Debug.Assert(node != null);
115 if (content == null) {
116 content = new List<XslNode>();
121 public void InsertContent(IEnumerable<XslNode> collection) {
122 if (content == null) {
123 content = new List<XslNode>(collection);
125 content.InsertRange(0, collection);
129 internal string TraceName {
132 System.Text.StringBuilder sb = new System.Text.StringBuilder();
135 case XslNodeType.AttributeSet : nodeTypeName = "attribute-set"; break;
136 case XslNodeType.Template : nodeTypeName = "template"; break;
137 case XslNodeType.Param : nodeTypeName = "param"; break;
138 case XslNodeType.Variable : nodeTypeName = "variable"; break;
139 case XslNodeType.WithParam : nodeTypeName = "with-param"; break;
140 default : nodeTypeName = NodeType.ToString(); break;
142 sb.Append(nodeTypeName);
145 sb.Append(Name.QualifiedName);
147 ISourceLineInfo lineInfo = SourceLine;
148 if (lineInfo == null && NodeType == XslNodeType.AttributeSet) {
149 lineInfo = Content[0].SourceLine;
150 Debug.Assert(lineInfo != null);
152 if (lineInfo != null) {
153 string fileName = SourceLineInfo.GetFileName(lineInfo.Uri);
154 int idx = fileName.LastIndexOf(System.IO.Path.DirectorySeparatorChar) + 1;
156 sb.Append(fileName, idx, fileName.Length - idx);
158 sb.Append(lineInfo.Start.Line);
161 return sb.ToString();
169 internal abstract class ProtoTemplate : XslNode {
170 public QilFunction Function; // Compiled body
172 public ProtoTemplate(XslNodeType nt, QilName name, XslVersion xslVer) : base(nt, name, null, xslVer) {}
173 public abstract string GetDebugName();
176 internal enum CycleCheck {
182 internal class AttributeSet : ProtoTemplate {
183 public CycleCheck CycleCheck; // Used to detect circular references
185 public AttributeSet(QilName name, XslVersion xslVer) : base(XslNodeType.AttributeSet, name, xslVer) {}
187 public override string GetDebugName() {
188 StringBuilder dbgName = new StringBuilder();
189 dbgName.Append("<xsl:attribute-set name=\"");
190 dbgName.Append(Name.QualifiedName);
191 dbgName.Append("\">");
192 return dbgName.ToString();
195 public new void AddContent(XslNode node) {
196 Debug.Assert(node != null && node.NodeType == XslNodeType.List);
197 base.AddContent(node);
200 public void MergeContent(AttributeSet other) {
201 InsertContent(other.Content);
205 internal class Template : ProtoTemplate {
206 public readonly string Match;
207 public readonly QilName Mode;
208 public readonly double Priority;
209 public int ImportPrecedence;
210 public int OrderNumber;
212 public Template(QilName name, string match, QilName mode, double priority, XslVersion xslVer)
213 : base(XslNodeType.Template, name, xslVer)
217 this.Priority = priority;
220 public override string GetDebugName() {
221 StringBuilder dbgName = new StringBuilder();
222 dbgName.Append("<xsl:template");
224 dbgName.Append(" match=\"");
225 dbgName.Append(Match);
229 dbgName.Append(" name=\"");
230 dbgName.Append(Name.QualifiedName);
233 if (!double.IsNaN(Priority)) {
234 dbgName.Append(" priority=\"");
235 dbgName.Append(Priority.ToString(CultureInfo.InvariantCulture));
238 if (Mode.LocalName.Length != 0) {
239 dbgName.Append(" mode=\"");
240 dbgName.Append(Mode.QualifiedName);
244 return dbgName.ToString();
248 internal class VarPar : XslNode {
249 public XslFlags DefValueFlags;
250 public QilNode Value; // Contains value for WithParams and global VarPars
252 public VarPar(XslNodeType nt, QilName name, string select, XslVersion xslVer) : base(nt, name, select, xslVer) {}
255 internal class Sort : XslNode {
256 public readonly string Lang;
257 public readonly string DataType;
258 public readonly string Order;
259 public readonly string CaseOrder;
261 public Sort(string select, string lang, string dataType, string order, string caseOrder, XslVersion xslVer)
262 : base(XslNodeType.Sort, null, select, xslVer)
265 this.DataType = dataType;
267 this.CaseOrder = caseOrder;
271 internal class Keys : KeyedCollection<QilName, List<Key>> {
272 protected override QilName GetKeyForItem(List<Key> list) {
273 Debug.Assert(list != null && list.Count > 0);
278 internal class Key : XslNode {
279 public readonly string Match;
280 public readonly string Use;
281 public QilFunction Function;
283 public Key(QilName name, string match, string use, XslVersion xslVer)
284 : base(XslNodeType.Key, name, null, xslVer)
286 // match and use can be null in case of incorrect stylesheet
287 Debug.Assert(name != null);
292 public string GetDebugName() {
293 StringBuilder dbgName = new StringBuilder();
294 dbgName.Append("<xsl:key name=\"");
295 dbgName.Append(Name.QualifiedName);
299 dbgName.Append(" match=\"");
300 dbgName.Append(Match);
304 dbgName.Append(" use=\"");
309 return dbgName.ToString();
313 internal enum NumberLevel {
319 internal class Number : XslNode {
320 public readonly NumberLevel Level;
321 public readonly string Count;
322 public readonly string From;
323 public readonly string Value;
324 public readonly string Format;
325 public readonly string Lang;
326 public readonly string LetterValue;
327 public readonly string GroupingSeparator;
328 public readonly string GroupingSize;
330 public Number(NumberLevel level, string count, string from, string value,
331 string format, string lang, string letterValue, string groupingSeparator, string groupingSize,
332 XslVersion xslVer) : base(XslNodeType.Number, null, null, xslVer)
338 this.Format = format;
340 this.LetterValue = letterValue;
341 this.GroupingSeparator = groupingSeparator;
342 this.GroupingSize = groupingSize;
346 internal class NodeCtor : XslNode {
347 public readonly string NameAvt;
348 public readonly string NsAvt;
350 public NodeCtor(XslNodeType nt, string nameAvt, string nsAvt, XslVersion xslVer)
351 : base(nt, null, null, xslVer)
353 this.NameAvt = nameAvt;
358 internal class Text : XslNode {
359 public readonly SerializationHints Hints;
361 public Text(string data, SerializationHints hints, XslVersion xslVer)
362 : base(XslNodeType.Text, null, data, xslVer)
368 internal class XslNodeEx : XslNode {
369 public readonly ISourceLineInfo ElemNameLi;
370 public readonly ISourceLineInfo EndTagLi;
372 public XslNodeEx(XslNodeType t, QilName name, object arg, ContextInfo ctxInfo, XslVersion xslVer)
373 : base(t, name, arg, xslVer)
375 ElemNameLi = ctxInfo.elemNameLi;
376 EndTagLi = ctxInfo.endTagLi;
379 public XslNodeEx(XslNodeType t, QilName name, object arg, XslVersion xslVer) : base(t, name, arg, xslVer) {
383 internal static class AstFactory {
384 public static XslNode XslNode(XslNodeType nodeType, QilName name, string arg, XslVersion xslVer) {
385 return new XslNode(nodeType, name, arg, xslVer);
388 public static XslNode ApplyImports(QilName mode, Stylesheet sheet, XslVersion xslVer) {
389 return new XslNode(XslNodeType.ApplyImports, mode, sheet, xslVer);
392 public static XslNodeEx ApplyTemplates(QilName mode, string select, ContextInfo ctxInfo, XslVersion xslVer) {
393 return new XslNodeEx(XslNodeType.ApplyTemplates, mode, select, ctxInfo, xslVer);
396 // Special node for start apply-templates
397 public static XslNodeEx ApplyTemplates(QilName mode) {
398 return new XslNodeEx(XslNodeType.ApplyTemplates, mode, /*select:*/null, XslVersion.Current);
401 public static NodeCtor Attribute(string nameAvt, string nsAvt, XslVersion xslVer) {
402 return new NodeCtor(XslNodeType.Attribute, nameAvt, nsAvt, xslVer);
405 public static AttributeSet AttributeSet(QilName name) {
406 return new AttributeSet(name, XslVersion.Current);
409 public static XslNodeEx CallTemplate(QilName name, ContextInfo ctxInfo) {
410 return new XslNodeEx(XslNodeType.CallTemplate, name, null, ctxInfo, XslVersion.Current);
413 public static XslNode Choose() {
414 return new XslNode(XslNodeType.Choose);
417 public static XslNode Comment() {
418 return new XslNode(XslNodeType.Comment);
421 public static XslNode Copy() {
422 return new XslNode(XslNodeType.Copy);
425 public static XslNode CopyOf(string select, XslVersion xslVer) {
426 return new XslNode(XslNodeType.CopyOf, null, select, xslVer);
429 public static NodeCtor Element(string nameAvt, string nsAvt, XslVersion xslVer) {
430 return new NodeCtor(XslNodeType.Element, nameAvt, nsAvt, xslVer);
433 public static XslNode Error(string message) {
434 return new XslNode(XslNodeType.Error, null, message, XslVersion.Current);
437 public static XslNodeEx ForEach(string select, ContextInfo ctxInfo, XslVersion xslVer) {
438 return new XslNodeEx(XslNodeType.ForEach, null, select, ctxInfo, xslVer);
441 public static XslNode If(string test, XslVersion xslVer) {
442 return new XslNode(XslNodeType.If, null, test, xslVer);
445 public static Key Key(QilName name, string match, string use, XslVersion xslVer) {
446 return new Key(name, match, use, xslVer);
449 public static XslNode List() {
450 return new XslNode(XslNodeType.List);
453 public static XslNode LiteralAttribute(QilName name, string value, XslVersion xslVer) {
454 return new XslNode(XslNodeType.LiteralAttribute, name, value, xslVer);
457 public static XslNode LiteralElement(QilName name) {
458 return new XslNode(XslNodeType.LiteralElement, name, null, XslVersion.Current);
461 public static XslNode Message(bool term) {
462 return new XslNode(XslNodeType.Message, null, term, XslVersion.Current);
465 public static XslNode Nop() {
466 return new XslNode(XslNodeType.Nop);
469 public static Number Number(NumberLevel level, string count, string from, string value,
470 string format, string lang, string letterValue, string groupingSeparator, string groupingSize,
473 return new Number(level, count, from, value, format, lang, letterValue, groupingSeparator, groupingSize, xslVer);
476 public static XslNode Otherwise() {
477 return new XslNode(XslNodeType.Otherwise);
480 public static XslNode PI(string name, XslVersion xslVer) {
481 return new XslNode(XslNodeType.PI, null, name, xslVer);
484 public static Sort Sort(string select, string lang, string dataType, string order, string caseOrder, XslVersion xslVer) {
485 return new Sort(select, lang, dataType, order, caseOrder, xslVer);
488 public static Template Template(QilName name, string match, QilName mode, double priority, XslVersion xslVer) {
489 return new Template(name, match, mode, priority, xslVer);
492 public static XslNode Text(string data) {
493 return new Text(data, SerializationHints.None, XslVersion.Current);
496 public static XslNode Text(string data, SerializationHints hints) {
497 return new Text(data, hints, XslVersion.Current);
500 public static XslNode UseAttributeSet(QilName name) {
501 return new XslNode(XslNodeType.UseAttributeSet, name, null, XslVersion.Current);
504 public static VarPar VarPar(XslNodeType nt, QilName name, string select, XslVersion xslVer) {
505 return new VarPar(nt, name, select, xslVer);
508 public static VarPar WithParam(QilName name) {
509 return VarPar(XslNodeType.WithParam, name, /*select*/null, XslVersion.Current);
512 private static QilFactory f = new QilFactory();
514 public static QilName QName(string local, string uri, string prefix) {
515 return f.LiteralQName(local, uri, prefix);
518 public static QilName QName(string local) {
519 return f.LiteralQName(local);