Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / XmlUtils / System / Xml / Xsl / QIL / QilXmlWriter.cs / 2 / QilXmlWriter.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// [....]
//-----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Xml;
namespace System.Xml.Xsl.Qil {
///
/// If an annotation implements this interface, then QilXmlWriter will call ToString() on the annotation
/// and serialize the result (if non-empty).
///
interface IQilAnnotation {
string Name { get; }
};
///
/// An example of QilVisitor. Prints the QilExpression tree as XML.
///
///
/// The QilXmlWriter Visits every node in the tree, printing out an XML representation of
/// each node. Several formatting options are available, including whether or not to include annotations
/// and type information. When full information is printed out, the graph can be reloaded from
/// its serialized form using QilXmlReader.
/// The XML format essentially uses one XML element for each node in the QIL graph.
/// Node properties such as type information are serialized as XML attributes.
/// Annotations are serialized as processing-instructions in front of a node.
/// Feel free to subclass this visitor to customize its behavior.
///
internal class QilXmlWriter : QilScopedVisitor {
protected XmlWriter writer;
protected Options options;
private NameGenerator ngen;
[Flags]
public enum Options {
None = 0, // No options selected
Annotations = 1, // Print annotations
TypeInfo = 2, // Print type information using "G" option
RoundTripTypeInfo = 4, // Print type information using "S" option
LineInfo = 8, // Print source line information
NodeIdentity = 16, // Print node identity (only works if QIL_TRACE_NODE_CREATION is defined)
NodeLocation = 32, // Print node creation location (only works if QIL_TRACE_NODE_CREATION is defined)
};
///
/// Construct a QilXmlWriter.
///
public QilXmlWriter(XmlWriter writer) : this(writer, Options.Annotations | Options.TypeInfo | Options.LineInfo | Options.NodeIdentity | Options.NodeLocation) {
}
///
/// Construct a QilXmlWriter.
///
public QilXmlWriter(XmlWriter writer, Options options) {
this.writer = writer;
this.ngen = new NameGenerator();
this.options = options;
}
///
/// Serialize a QilExpression graph as XML.
///
/// the QilExpression graph
public void ToXml(QilNode node) {
VisitAssumeReference(node);
}
//-----------------------------------------------
// QilXmlWrite methods
//-----------------------------------------------
///
/// Write all annotations as comments:
/// 1. string --
/// 2. IQilAnnotation --
/// 3. IList -- recursively call WriteAnnotations for each object in list
/// 4. otherwise, do not write the annotation
///
protected virtual void WriteAnnotations(object ann) {
string s = null, name = null;
if (ann == null) {
return;
}
else if (ann is string) {
s = ann as string;
}
else if (ann is IQilAnnotation) {
// Get annotation's name and string value
IQilAnnotation qilann = ann as IQilAnnotation;
name = qilann.Name;
s = ann.ToString();
}
else if (ann is IList) {
IList list = (IList) ann;
foreach (object annItem in list)
WriteAnnotations(annItem);
return;
}
if (s != null && s.Length != 0)
this.writer.WriteComment(name != null && name.Length != 0 ? name + ": " + s : s);
}
///
/// Called in order to write out source line information.
///
protected virtual void WriteLineInfo(QilNode node) {
this.writer.WriteAttributeString("lineInfo", string.Format(CultureInfo.InvariantCulture, "[{0},{1} -- {2},{3}]",
node.SourceLine.StartLine, node.SourceLine.StartPos,
node.SourceLine.EndLine , node.SourceLine.EndPos
));
}
///
/// Called in order to write out the xml type of a node.
///
protected virtual void WriteXmlType(QilNode node) {
this.writer.WriteAttributeString("xmlType", node.XmlType.ToString((this.options & Options.RoundTripTypeInfo) != 0 ? "S" : "G"));
}
//-----------------------------------------------
// QilVisitor overrides
//-----------------------------------------------
///
/// Override certain node types in order to add additional attributes, suppress children, etc.
///
protected override QilNode VisitChildren(QilNode node) {
if (node is QilLiteral) {
// If literal is not handled elsewhere, print its string value
this.writer.WriteValue(Convert.ToString(((QilLiteral) node).Value, CultureInfo.InvariantCulture));
return node;
}
else if (node is QilReference) {
QilReference reference = (QilReference) node;
// Write the generated identifier for this iterator
this.writer.WriteAttributeString("id", this.ngen.NameOf(node));
// Write the debug name of this reference (if it's defined) as a "name" attribute
if (reference.DebugName != null)
this.writer.WriteAttributeString("name", reference.DebugName.ToString());
if (node.NodeType == QilNodeType.Parameter) {
// Don't visit parameter's name, or its default value if it is null
QilParameter param = (QilParameter) node;
if (param.DefaultValue != null)
Visit(param.DefaultValue);
return node;
}
}
return base.VisitChildren(node);
}
///
/// Write references to functions or iterators like this: .
///
protected override QilNode VisitReference(QilNode node) {
QilReference reference = (QilReference) node;
string name = ngen.NameOf(node);
if (name == null)
name = "OUT-OF-SCOPE REFERENCE";
this.writer.WriteStartElement("RefTo");
this.writer.WriteAttributeString("id", name);
if (reference.DebugName != null)
this.writer.WriteAttributeString("name", reference.DebugName.ToString());
this.writer.WriteEndElement();
return node;
}
///
/// Scan through the external parameters, global variables, and function list for forward references.
///
protected override QilNode VisitQilExpression(QilExpression qil) {
IList fdecls = new ForwardRefFinder().Find(qil);
if (fdecls != null && fdecls.Count > 0) {
this.writer.WriteStartElement("ForwardDecls");
foreach (QilNode n in fdecls) {
// i.e.
this.writer.WriteStartElement(Enum.GetName(typeof(QilNodeType), n.NodeType));
this.writer.WriteAttributeString("id", this.ngen.NameOf(n));
WriteXmlType(n);
if (n.NodeType == QilNodeType.Function) {
// Visit Arguments and SideEffects operands
Visit(n[0]);
Visit(n[2]);
}
this.writer.WriteEndElement();
}
this.writer.WriteEndElement();
}
return VisitChildren(qil);
}
///
/// Serialize literal types using either "S" or "G" formatting, depending on the option which has been set.
///
protected override QilNode VisitLiteralType(QilLiteral value) {
this.writer.WriteString(((XmlQueryType) value).ToString((this.options & Options.TypeInfo) != 0 ? "G" : "S"));
return value;
}
///
/// Serialize literal QName as three separate attributes.
///
protected override QilNode VisitLiteralQName(QilName value) {
this.writer.WriteAttributeString("name", value.ToString());
return value;
}
//-----------------------------------------------
// QilScopedVisitor overrides
//-----------------------------------------------
///
/// Annotate this iterator or function with a generated name.
///
protected override void BeginScope(QilNode node) {
this.ngen.NameOf(node);
}
///
/// Clear the name annotation on this iterator or function.
///
protected override void EndScope(QilNode node) {
this.ngen.ClearName(node);
}
///
/// By default, call WriteStartElement for every node type.
///
protected override void BeforeVisit(QilNode node) {
base.BeforeVisit(node);
// Write the annotations in front of the element, to avoid issues with attributes
// and make it easier to round-trip
if ((this.options & Options.Annotations) != 0)
WriteAnnotations(node.Annotation);
// Call WriteStartElement
this.writer.WriteStartElement("", Enum.GetName(typeof(QilNodeType), node.NodeType), "");
// Write common attributes
#if QIL_TRACE_NODE_CREATION
if ((this.options & Options.NodeIdentity) != 0)
this.writer.WriteAttributeString("nodeId", node.NodeId.ToString(CultureInfo.InvariantCulture));
if ((this.options & Options.NodeLocation) != 0)
this.writer.WriteAttributeString("nodeLoc", node.NodeLocation);
#endif
if ((this.options & (Options.TypeInfo | Options.RoundTripTypeInfo)) != 0)
WriteXmlType(node);
if ((this.options & Options.LineInfo) != 0 && node.SourceLine != null)
WriteLineInfo(node);
}
///
/// By default, call WriteEndElement for every node type.
///
protected override void AfterVisit(QilNode node) {
this.writer.WriteEndElement();
base.AfterVisit(node);
}
//-----------------------------------------------
// Helper methods
//-----------------------------------------------
///
/// Find list of all iterators and functions which are referenced before they have been declared.
///
internal class ForwardRefFinder : QilVisitor {
private List fwdrefs = new List();
private List backrefs = new List();
public IList Find(QilExpression qil) {
Visit(qil);
return this.fwdrefs;
}
///
/// Add iterators and functions to backrefs list as they are visited.
///
protected override QilNode Visit(QilNode node) {
if (node is QilIterator || node is QilFunction)
this.backrefs.Add(node);
return base.Visit(node);
}
///
/// If reference is not in scope, then it must be a forward reference.
///
protected override QilNode VisitReference(QilNode node) {
if (!this.backrefs.Contains(node) && !this.fwdrefs.Contains(node))
this.fwdrefs.Add(node);
return node;
}
}
//=================================== Helper class: NameGenerator =========================================
private sealed class NameGenerator {
StringBuilder name;
int len;
int zero;
char start;
char end;
///
/// Construct a new name generator with prefix "$" and alphabetical mode.
///
public NameGenerator()
{
string prefix = "$";
len = zero = prefix.Length;
start = 'a';
end = 'z';
name = new StringBuilder(prefix, len + 2);
name.Append(start);
}
///
/// Skolem function for names.
///
/// a unique name beginning with the prefix
public string NextName()
{
string result = name.ToString();
char c = name[len];
if (c == end)
{
name[len] = start;
int i = len;
for ( ; i-- > zero && name[i]==end; )
name[i] = start;
if (i < zero)
{
len++;
name.Append(start);
}
else
name[i]++;
}
else
name[len] = ++c;
return result;
}
///
/// Lookup or generate a name for a node. Uses annotations to store the name on the node.
///
/// the node
/// the node name (unique across nodes)
public string NameOf(QilNode n)
{
string name = null;
object old = n.Annotation;
NameAnnotation a = old as NameAnnotation;
if (a == null)
{
name = NextName();
n.Annotation = new NameAnnotation(name, old);
}
else
{
name = a.Name;
}
return name;
}
///
/// Clear name annotation from a node.
///
/// the node
public void ClearName(QilNode n)
{
if (n.Annotation is NameAnnotation)
n.Annotation = ((NameAnnotation)n.Annotation).PriorAnnotation;
}
///
/// Class used to hold our annotations on the graph
///
private class NameAnnotation : ListBase
{
public string Name;
public object PriorAnnotation;
public NameAnnotation(string s, object a)
{
Name = s;
PriorAnnotation = a;
}
public override int Count {
get { return 1; }
}
public override object this[int index] {
get {
if (index == 0)
return PriorAnnotation;
throw new IndexOutOfRangeException();
}
set { throw new NotSupportedException(); }
}
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// [....]
//-----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Xml;
namespace System.Xml.Xsl.Qil {
///
/// If an annotation implements this interface, then QilXmlWriter will call ToString() on the annotation
/// and serialize the result (if non-empty).
///
interface IQilAnnotation {
string Name { get; }
};
///
/// An example of QilVisitor. Prints the QilExpression tree as XML.
///
///
/// The QilXmlWriter Visits every node in the tree, printing out an XML representation of
/// each node. Several formatting options are available, including whether or not to include annotations
/// and type information. When full information is printed out, the graph can be reloaded from
/// its serialized form using QilXmlReader.
/// The XML format essentially uses one XML element for each node in the QIL graph.
/// Node properties such as type information are serialized as XML attributes.
/// Annotations are serialized as processing-instructions in front of a node.
/// Feel free to subclass this visitor to customize its behavior.
///
internal class QilXmlWriter : QilScopedVisitor {
protected XmlWriter writer;
protected Options options;
private NameGenerator ngen;
[Flags]
public enum Options {
None = 0, // No options selected
Annotations = 1, // Print annotations
TypeInfo = 2, // Print type information using "G" option
RoundTripTypeInfo = 4, // Print type information using "S" option
LineInfo = 8, // Print source line information
NodeIdentity = 16, // Print node identity (only works if QIL_TRACE_NODE_CREATION is defined)
NodeLocation = 32, // Print node creation location (only works if QIL_TRACE_NODE_CREATION is defined)
};
///
/// Construct a QilXmlWriter.
///
public QilXmlWriter(XmlWriter writer) : this(writer, Options.Annotations | Options.TypeInfo | Options.LineInfo | Options.NodeIdentity | Options.NodeLocation) {
}
///
/// Construct a QilXmlWriter.
///
public QilXmlWriter(XmlWriter writer, Options options) {
this.writer = writer;
this.ngen = new NameGenerator();
this.options = options;
}
///
/// Serialize a QilExpression graph as XML.
///
/// the QilExpression graph
public void ToXml(QilNode node) {
VisitAssumeReference(node);
}
//-----------------------------------------------
// QilXmlWrite methods
//-----------------------------------------------
///
/// Write all annotations as comments:
/// 1. string --
/// 2. IQilAnnotation --
/// 3. IList -- recursively call WriteAnnotations for each object in list
/// 4. otherwise, do not write the annotation
///
protected virtual void WriteAnnotations(object ann) {
string s = null, name = null;
if (ann == null) {
return;
}
else if (ann is string) {
s = ann as string;
}
else if (ann is IQilAnnotation) {
// Get annotation's name and string value
IQilAnnotation qilann = ann as IQilAnnotation;
name = qilann.Name;
s = ann.ToString();
}
else if (ann is IList) {
IList list = (IList) ann;
foreach (object annItem in list)
WriteAnnotations(annItem);
return;
}
if (s != null && s.Length != 0)
this.writer.WriteComment(name != null && name.Length != 0 ? name + ": " + s : s);
}
///
/// Called in order to write out source line information.
///
protected virtual void WriteLineInfo(QilNode node) {
this.writer.WriteAttributeString("lineInfo", string.Format(CultureInfo.InvariantCulture, "[{0},{1} -- {2},{3}]",
node.SourceLine.StartLine, node.SourceLine.StartPos,
node.SourceLine.EndLine , node.SourceLine.EndPos
));
}
///
/// Called in order to write out the xml type of a node.
///
protected virtual void WriteXmlType(QilNode node) {
this.writer.WriteAttributeString("xmlType", node.XmlType.ToString((this.options & Options.RoundTripTypeInfo) != 0 ? "S" : "G"));
}
//-----------------------------------------------
// QilVisitor overrides
//-----------------------------------------------
///
/// Override certain node types in order to add additional attributes, suppress children, etc.
///
protected override QilNode VisitChildren(QilNode node) {
if (node is QilLiteral) {
// If literal is not handled elsewhere, print its string value
this.writer.WriteValue(Convert.ToString(((QilLiteral) node).Value, CultureInfo.InvariantCulture));
return node;
}
else if (node is QilReference) {
QilReference reference = (QilReference) node;
// Write the generated identifier for this iterator
this.writer.WriteAttributeString("id", this.ngen.NameOf(node));
// Write the debug name of this reference (if it's defined) as a "name" attribute
if (reference.DebugName != null)
this.writer.WriteAttributeString("name", reference.DebugName.ToString());
if (node.NodeType == QilNodeType.Parameter) {
// Don't visit parameter's name, or its default value if it is null
QilParameter param = (QilParameter) node;
if (param.DefaultValue != null)
Visit(param.DefaultValue);
return node;
}
}
return base.VisitChildren(node);
}
///
/// Write references to functions or iterators like this: .
///
protected override QilNode VisitReference(QilNode node) {
QilReference reference = (QilReference) node;
string name = ngen.NameOf(node);
if (name == null)
name = "OUT-OF-SCOPE REFERENCE";
this.writer.WriteStartElement("RefTo");
this.writer.WriteAttributeString("id", name);
if (reference.DebugName != null)
this.writer.WriteAttributeString("name", reference.DebugName.ToString());
this.writer.WriteEndElement();
return node;
}
///
/// Scan through the external parameters, global variables, and function list for forward references.
///
protected override QilNode VisitQilExpression(QilExpression qil) {
IList fdecls = new ForwardRefFinder().Find(qil);
if (fdecls != null && fdecls.Count > 0) {
this.writer.WriteStartElement("ForwardDecls");
foreach (QilNode n in fdecls) {
// i.e.
this.writer.WriteStartElement(Enum.GetName(typeof(QilNodeType), n.NodeType));
this.writer.WriteAttributeString("id", this.ngen.NameOf(n));
WriteXmlType(n);
if (n.NodeType == QilNodeType.Function) {
// Visit Arguments and SideEffects operands
Visit(n[0]);
Visit(n[2]);
}
this.writer.WriteEndElement();
}
this.writer.WriteEndElement();
}
return VisitChildren(qil);
}
///
/// Serialize literal types using either "S" or "G" formatting, depending on the option which has been set.
///
protected override QilNode VisitLiteralType(QilLiteral value) {
this.writer.WriteString(((XmlQueryType) value).ToString((this.options & Options.TypeInfo) != 0 ? "G" : "S"));
return value;
}
///
/// Serialize literal QName as three separate attributes.
///
protected override QilNode VisitLiteralQName(QilName value) {
this.writer.WriteAttributeString("name", value.ToString());
return value;
}
//-----------------------------------------------
// QilScopedVisitor overrides
//-----------------------------------------------
///
/// Annotate this iterator or function with a generated name.
///
protected override void BeginScope(QilNode node) {
this.ngen.NameOf(node);
}
///
/// Clear the name annotation on this iterator or function.
///
protected override void EndScope(QilNode node) {
this.ngen.ClearName(node);
}
///
/// By default, call WriteStartElement for every node type.
///
protected override void BeforeVisit(QilNode node) {
base.BeforeVisit(node);
// Write the annotations in front of the element, to avoid issues with attributes
// and make it easier to round-trip
if ((this.options & Options.Annotations) != 0)
WriteAnnotations(node.Annotation);
// Call WriteStartElement
this.writer.WriteStartElement("", Enum.GetName(typeof(QilNodeType), node.NodeType), "");
// Write common attributes
#if QIL_TRACE_NODE_CREATION
if ((this.options & Options.NodeIdentity) != 0)
this.writer.WriteAttributeString("nodeId", node.NodeId.ToString(CultureInfo.InvariantCulture));
if ((this.options & Options.NodeLocation) != 0)
this.writer.WriteAttributeString("nodeLoc", node.NodeLocation);
#endif
if ((this.options & (Options.TypeInfo | Options.RoundTripTypeInfo)) != 0)
WriteXmlType(node);
if ((this.options & Options.LineInfo) != 0 && node.SourceLine != null)
WriteLineInfo(node);
}
///
/// By default, call WriteEndElement for every node type.
///
protected override void AfterVisit(QilNode node) {
this.writer.WriteEndElement();
base.AfterVisit(node);
}
//-----------------------------------------------
// Helper methods
//-----------------------------------------------
///
/// Find list of all iterators and functions which are referenced before they have been declared.
///
internal class ForwardRefFinder : QilVisitor {
private List fwdrefs = new List();
private List backrefs = new List();
public IList Find(QilExpression qil) {
Visit(qil);
return this.fwdrefs;
}
///
/// Add iterators and functions to backrefs list as they are visited.
///
protected override QilNode Visit(QilNode node) {
if (node is QilIterator || node is QilFunction)
this.backrefs.Add(node);
return base.Visit(node);
}
///
/// If reference is not in scope, then it must be a forward reference.
///
protected override QilNode VisitReference(QilNode node) {
if (!this.backrefs.Contains(node) && !this.fwdrefs.Contains(node))
this.fwdrefs.Add(node);
return node;
}
}
//=================================== Helper class: NameGenerator =========================================
private sealed class NameGenerator {
StringBuilder name;
int len;
int zero;
char start;
char end;
///
/// Construct a new name generator with prefix "$" and alphabetical mode.
///
public NameGenerator()
{
string prefix = "$";
len = zero = prefix.Length;
start = 'a';
end = 'z';
name = new StringBuilder(prefix, len + 2);
name.Append(start);
}
///
/// Skolem function for names.
///
/// a unique name beginning with the prefix
public string NextName()
{
string result = name.ToString();
char c = name[len];
if (c == end)
{
name[len] = start;
int i = len;
for ( ; i-- > zero && name[i]==end; )
name[i] = start;
if (i < zero)
{
len++;
name.Append(start);
}
else
name[i]++;
}
else
name[len] = ++c;
return result;
}
///
/// Lookup or generate a name for a node. Uses annotations to store the name on the node.
///
/// the node
/// the node name (unique across nodes)
public string NameOf(QilNode n)
{
string name = null;
object old = n.Annotation;
NameAnnotation a = old as NameAnnotation;
if (a == null)
{
name = NextName();
n.Annotation = new NameAnnotation(name, old);
}
else
{
name = a.Name;
}
return name;
}
///
/// Clear name annotation from a node.
///
/// the node
public void ClearName(QilNode n)
{
if (n.Annotation is NameAnnotation)
n.Annotation = ((NameAnnotation)n.Annotation).PriorAnnotation;
}
///
/// Class used to hold our annotations on the graph
///
private class NameAnnotation : ListBase
{
public string Name;
public object PriorAnnotation;
public NameAnnotation(string s, object a)
{
Name = s;
PriorAnnotation = a;
}
public override int Count {
get { return 1; }
}
public override object this[int index] {
get {
if (index == 0)
return PriorAnnotation;
throw new IndexOutOfRangeException();
}
set { throw new NotSupportedException(); }
}
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.