e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
265 lines
11 KiB
C#
265 lines
11 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="RootAction.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
// <owner current="true" primary="true">[....]</owner>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Xml.Xsl.XsltOld {
|
|
using Res = System.Xml.Utils.Res;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Xml;
|
|
using System.Xml.XPath;
|
|
using System.Xml.Xsl.Runtime;
|
|
using MS.Internal.Xml.XPath;
|
|
using System.Security;
|
|
|
|
internal class Key {
|
|
XmlQualifiedName name;
|
|
int matchKey;
|
|
int useKey;
|
|
ArrayList keyNodes;
|
|
|
|
public Key(XmlQualifiedName name, int matchkey, int usekey) {
|
|
this.name = name;
|
|
this.matchKey = matchkey;
|
|
this.useKey = usekey;
|
|
this.keyNodes = null;
|
|
}
|
|
|
|
public XmlQualifiedName Name { get { return this.name; } }
|
|
public int MatchKey { get { return this.matchKey; } }
|
|
public int UseKey { get { return this.useKey; } }
|
|
|
|
public void AddKey(XPathNavigator root, Hashtable table) {
|
|
if (this.keyNodes == null) {
|
|
this.keyNodes = new ArrayList();
|
|
}
|
|
this.keyNodes.Add(new DocumentKeyList(root, table));
|
|
}
|
|
|
|
public Hashtable GetKeys(XPathNavigator root) {
|
|
if (this.keyNodes != null) {
|
|
for(int i=0; i < keyNodes.Count; i++) {
|
|
if (((DocumentKeyList)keyNodes[i]).RootNav.IsSamePosition(root)) {
|
|
return ((DocumentKeyList)keyNodes[i]).KeyTable;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public Key Clone() {
|
|
return new Key(name, matchKey, useKey);
|
|
}
|
|
}
|
|
|
|
internal struct DocumentKeyList {
|
|
XPathNavigator rootNav;
|
|
Hashtable keyTable;
|
|
|
|
public DocumentKeyList(XPathNavigator rootNav, Hashtable keyTable) {
|
|
this.rootNav = rootNav;
|
|
this.keyTable = keyTable;
|
|
}
|
|
|
|
public XPathNavigator RootNav { get { return this.rootNav ; } }
|
|
public Hashtable KeyTable { get { return this.keyTable; } }
|
|
}
|
|
|
|
internal class RootAction : TemplateBaseAction {
|
|
private const int QueryInitialized = 2;
|
|
private const int RootProcessed = 3;
|
|
|
|
private Hashtable attributeSetTable = new Hashtable();
|
|
private Hashtable decimalFormatTable = new Hashtable();
|
|
private List<Key> keyList;
|
|
private XsltOutput output;
|
|
public Stylesheet builtInSheet;
|
|
public PermissionSet permissions;
|
|
|
|
internal XsltOutput Output {
|
|
get {
|
|
if (this.output == null) {
|
|
this.output = new XsltOutput();
|
|
}
|
|
return this.output;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Compile
|
|
*/
|
|
internal override void Compile(Compiler compiler) {
|
|
CompileDocument(compiler, /*inInclude*/ false);
|
|
}
|
|
|
|
internal void InsertKey(XmlQualifiedName name, int MatchKey, int UseKey){
|
|
if (this.keyList == null) {
|
|
this.keyList = new List<Key>();
|
|
}
|
|
this.keyList.Add(new Key(name, MatchKey, UseKey));
|
|
}
|
|
|
|
internal AttributeSetAction GetAttributeSet(XmlQualifiedName name) {
|
|
AttributeSetAction action = (AttributeSetAction) this.attributeSetTable[name];
|
|
if(action == null) {
|
|
throw XsltException.Create(Res.Xslt_NoAttributeSet, name.ToString());
|
|
}
|
|
return action;
|
|
}
|
|
|
|
|
|
public void PorcessAttributeSets(Stylesheet rootStylesheet) {
|
|
MirgeAttributeSets(rootStylesheet);
|
|
|
|
// As we mentioned we need to invert all lists.
|
|
foreach (AttributeSetAction attSet in this.attributeSetTable.Values) {
|
|
if (attSet.containedActions != null) {
|
|
attSet.containedActions.Reverse();
|
|
}
|
|
}
|
|
|
|
// ensures there are no cycles in the attribute-sets use dfs marking method
|
|
CheckAttributeSets_RecurceInList(new Hashtable(), this.attributeSetTable.Keys);
|
|
}
|
|
|
|
private void MirgeAttributeSets(Stylesheet stylesheet) {
|
|
// mirge stylesheet.AttributeSetTable to this.AttributeSetTable
|
|
|
|
if (stylesheet.AttributeSetTable != null) {
|
|
foreach (AttributeSetAction srcAttSet in stylesheet.AttributeSetTable.Values) {
|
|
ArrayList srcAttList = srcAttSet.containedActions;
|
|
AttributeSetAction dstAttSet = (AttributeSetAction) this.attributeSetTable[srcAttSet.Name];
|
|
if (dstAttSet == null) {
|
|
dstAttSet = new AttributeSetAction(); {
|
|
dstAttSet.name = srcAttSet.Name;
|
|
dstAttSet.containedActions = new ArrayList();
|
|
}
|
|
this.attributeSetTable[srcAttSet.Name] = dstAttSet;
|
|
}
|
|
ArrayList dstAttList = dstAttSet.containedActions;
|
|
// We adding attributes in reverse order for purpuse. In the mirged list most importent attset shoud go last one
|
|
// so we'll need to invert dstAttList finaly.
|
|
if (srcAttList != null) {
|
|
for(int src = srcAttList.Count - 1; 0 <= src; src --) {
|
|
// We can ignore duplicate attibutes here.
|
|
dstAttList.Add(srcAttList[src]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (Stylesheet importedStylesheet in stylesheet.Imports) {
|
|
MirgeAttributeSets(importedStylesheet);
|
|
}
|
|
}
|
|
|
|
private void CheckAttributeSets_RecurceInList(Hashtable markTable, ICollection setQNames) {
|
|
const string PROCESSING = "P";
|
|
const string DONE = "D";
|
|
|
|
foreach (XmlQualifiedName qname in setQNames) {
|
|
object mark = markTable[qname];
|
|
if (mark == (object) PROCESSING) {
|
|
throw XsltException.Create(Res.Xslt_CircularAttributeSet, qname.ToString());
|
|
} else if (mark == (object) DONE) {
|
|
continue; // optimization: we already investigated this attribute-set.
|
|
} else {
|
|
Debug.Assert(mark == null);
|
|
|
|
markTable[qname] = (object) PROCESSING;
|
|
CheckAttributeSets_RecurceInContainer(markTable, GetAttributeSet(qname));
|
|
markTable[qname] = (object) DONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CheckAttributeSets_RecurceInContainer(Hashtable markTable, ContainerAction container) {
|
|
if (container.containedActions == null) {
|
|
return;
|
|
}
|
|
foreach(Action action in container.containedActions) {
|
|
if(action is UseAttributeSetsAction) {
|
|
CheckAttributeSets_RecurceInList(markTable, ((UseAttributeSetsAction)action).UsedSets);
|
|
} else if(action is ContainerAction) {
|
|
CheckAttributeSets_RecurceInContainer(markTable, (ContainerAction)action);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void AddDecimalFormat(XmlQualifiedName name, DecimalFormat formatinfo) {
|
|
DecimalFormat exist = (DecimalFormat) this.decimalFormatTable[name];
|
|
if (exist != null) {
|
|
NumberFormatInfo info = exist.info;
|
|
NumberFormatInfo newinfo = formatinfo.info;
|
|
if (info.NumberDecimalSeparator != newinfo.NumberDecimalSeparator ||
|
|
info.NumberGroupSeparator != newinfo.NumberGroupSeparator ||
|
|
info.PositiveInfinitySymbol != newinfo.PositiveInfinitySymbol ||
|
|
info.NegativeSign != newinfo.NegativeSign ||
|
|
info.NaNSymbol != newinfo.NaNSymbol ||
|
|
info.PercentSymbol != newinfo.PercentSymbol ||
|
|
info.PerMilleSymbol != newinfo.PerMilleSymbol ||
|
|
exist.zeroDigit != formatinfo.zeroDigit ||
|
|
exist.digit != formatinfo.digit ||
|
|
exist.patternSeparator != formatinfo.patternSeparator
|
|
) {
|
|
throw XsltException.Create(Res.Xslt_DupDecimalFormat, name.ToString());
|
|
}
|
|
}
|
|
this.decimalFormatTable[name] = formatinfo;
|
|
}
|
|
|
|
internal DecimalFormat GetDecimalFormat(XmlQualifiedName name) {
|
|
return this.decimalFormatTable[name] as DecimalFormat;
|
|
}
|
|
|
|
internal List<Key> KeyList{
|
|
get { return this.keyList; }
|
|
}
|
|
|
|
internal override void Execute(Processor processor, ActionFrame frame) {
|
|
Debug.Assert(processor != null && frame != null);
|
|
|
|
switch (frame.State) {
|
|
case Initialized:
|
|
frame.AllocateVariables(variableCount);
|
|
XPathNavigator root = processor.Document.Clone();
|
|
root.MoveToRoot();
|
|
frame.InitNodeSet(new XPathSingletonIterator(root));
|
|
|
|
if (this.containedActions != null && this.containedActions.Count > 0) {
|
|
processor.PushActionFrame(frame);
|
|
}
|
|
frame.State = QueryInitialized;
|
|
break;
|
|
case QueryInitialized:
|
|
Debug.Assert(frame.State == QueryInitialized);
|
|
frame.NextNode(processor);
|
|
Debug.Assert(Processor.IsRoot(frame.Node));
|
|
if (processor.Debugger != null) {
|
|
// this is like apply-templates, but we don't have it on stack.
|
|
// Pop the stack, otherwise last instruction will be on it.
|
|
processor.PopDebuggerStack();
|
|
}
|
|
processor.PushTemplateLookup(frame.NodeSet, /*mode:*/null, /*importsOf:*/null);
|
|
|
|
frame.State = RootProcessed;
|
|
break;
|
|
|
|
case RootProcessed:
|
|
Debug.Assert(frame.State == RootProcessed);
|
|
frame.Finished();
|
|
break;
|
|
default:
|
|
Debug.Fail("Invalid RootAction execution state");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|