|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Diagnostics;
using System.Globalization;
using System.Xml;
namespace System.Xml.Xsl.XsltOld
{
internal sealed class OutputScopeManager
{
private const int STACK_INCREMENT = 10;
private readonly HWStack _elementScopesStack;
private string _defaultNS;
private readonly OutKeywords _atoms;
private readonly XmlNameTable _nameTable;
private int _prefixIndex;
internal string DefaultNamespace
{
get { return _defaultNS; }
}
internal OutputScope CurrentElementScope
{
get
{
Debug.Assert(_elementScopesStack.Peek() != null); // We adding rootElementScope to garantee this
return (OutputScope)_elementScopesStack.Peek()!;
}
}
internal XmlSpace XmlSpace
{
get { return CurrentElementScope.Space; }
}
internal string XmlLang
{
get { return CurrentElementScope.Lang; }
}
internal OutputScopeManager(XmlNameTable nameTable, OutKeywords atoms)
{
Debug.Assert(nameTable != null);
Debug.Assert(atoms != null);
_elementScopesStack = new HWStack(STACK_INCREMENT);
_nameTable = nameTable;
_atoms = atoms;
_defaultNS = _atoms.Empty;
// We always adding rootElementScope to garantee that CurrentElementScope != null
// This context is active between PI and first element for example
OutputScope rootElementScope = (OutputScope)_elementScopesStack.Push();
if (rootElementScope == null)
{
rootElementScope = new OutputScope();
_elementScopesStack.AddToTop(rootElementScope);
}
rootElementScope.Init(string.Empty, string.Empty, string.Empty, /*space:*/XmlSpace.None, /*lang:*/string.Empty, /*mixed:*/false);
}
internal void PushNamespace(string prefix, string nspace)
{
Debug.Assert(prefix != null);
Debug.Assert(nspace != null);
CurrentElementScope.AddNamespace(prefix, nspace, _defaultNS);
if (string.IsNullOrEmpty(prefix))
{
_defaultNS = nspace;
}
}
internal void PushScope(string name, string nspace, string prefix)
{
Debug.Assert(name != null);
Debug.Assert(nspace != null);
Debug.Assert(prefix != null);
OutputScope parentScope = CurrentElementScope;
OutputScope elementScope = (OutputScope)_elementScopesStack.Push();
if (elementScope == null)
{
elementScope = new OutputScope();
_elementScopesStack.AddToTop(elementScope);
}
Debug.Assert(elementScope != null);
elementScope.Init(name, nspace, prefix, parentScope.Space, parentScope.Lang, parentScope.Mixed);
}
internal void PopScope()
{
OutputScope? elementScope = (OutputScope?)_elementScopesStack.Pop();
Debug.Assert(elementScope != null); // We're adding rootElementScope to guarantee this
for (NamespaceDecl? scope = elementScope.Scopes; scope != null; scope = scope.Next)
{
_defaultNS = scope.PrevDefaultNsUri;
}
}
internal string? ResolveNamespace(string prefix)
{
return ResolveNamespace(prefix, out _);
}
internal string? ResolveNamespace(string prefix, out bool thisScope)
{
Debug.Assert(prefix != null);
thisScope = true;
if (string.IsNullOrEmpty(prefix))
{
return _defaultNS;
}
else
{
if (Ref.Equal(prefix, _atoms.Xml))
{
return _atoms.XmlNamespace;
}
else if (Ref.Equal(prefix, _atoms.Xmlns))
{
return _atoms.XmlnsNamespace;
}
for (int i = _elementScopesStack.Length - 1; i >= 0; i--)
{
Debug.Assert(_elementScopesStack[i] is OutputScope);
OutputScope elementScope = (OutputScope)_elementScopesStack[i];
string? nspace = elementScope.ResolveAtom(prefix);
if (nspace != null)
{
thisScope = (i == _elementScopesStack.Length - 1);
return nspace;
}
}
}
return null;
}
internal bool FindPrefix(string nspace, out string? prefix)
{
Debug.Assert(nspace != null);
for (int i = _elementScopesStack.Length - 1; 0 <= i; i--)
{
Debug.Assert(_elementScopesStack[i] is OutputScope);
OutputScope elementScope = (OutputScope)_elementScopesStack[i];
string? pfx;
if (elementScope.FindPrefix(nspace, out pfx))
{
string? testNspace = ResolveNamespace(pfx);
if (testNspace != null && Ref.Equal(testNspace, nspace))
{
prefix = pfx;
return true;
}
else
{
break;
}
}
}
prefix = null;
return false;
}
internal string GeneratePrefix(string format)
{
string prefix;
do
{
prefix = string.Format(CultureInfo.InvariantCulture, format, _prefixIndex++);
} while (_nameTable.Get(prefix) != null);
return _nameTable.Add(prefix);
}
}
}
|