1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
//------------------------------------------------------------------------------
// <copyright file="OutputScopeManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Xml;
using System.Collections;
namespace System.Xml.Xsl.Xslt {
internal class OutputScopeManager {
public struct ScopeReord {
public int scopeCount;
public string prefix;
public string nsUri;
}
ScopeReord[] records = new ScopeReord[32];
int lastRecord = 0;
int lastScopes = 0; // This is cash of records[lastRecord].scopeCount field;
// most often we will have PushScope()/PopScope pare over the same record.
// It has sence to avoid adresing this field through array access.
public OutputScopeManager() {
Reset();
}
public void Reset() {
// AddNamespace(null, null); -- lookup barier
records[0].prefix = null;
records[0].nsUri = null;
PushScope();
}
public void PushScope() {
lastScopes ++;
}
public void PopScope() {
if (0 < lastScopes) {
lastScopes --;
}
else {
while(records[-- lastRecord].scopeCount == 0) ;
lastScopes = records[lastRecord].scopeCount;
lastScopes --;
}
}
// This can be ns declaration or ns exclussion. Las one when prefix == null;
public void AddNamespace(string prefix, string uri) {
Debug.Assert(prefix != null);
Debug.Assert(uri != null);
// uri = nameTable.Add(uri);
AddRecord(prefix, uri);
}
private void AddRecord(string prefix, string uri) {
records[lastRecord].scopeCount = lastScopes;
lastRecord ++;
if (lastRecord == records.Length) {
ScopeReord[] newRecords = new ScopeReord[lastRecord * 2];
Array.Copy(records, 0, newRecords, 0, lastRecord);
records = newRecords;
}
lastScopes = 0;
records[lastRecord].prefix = prefix;
records[lastRecord].nsUri = uri;
}
// There are some cases where we can't predict namespace content. To garantee correct results we should output all
// literal namespaces once again.
// <xsl:element name="{}" namespace="{}"> all prefixes should be invalidated
// <xsl:element name="{}" namespace="FOO"> all prefixes should be invalidated
// <xsl:element name="foo:A" namespace="{}"> prefixe "foo" should be invalidated
// <xsl:element name="foo:{}" namespace="{}"> prefixe "foo" should be invalidated
// <xsl:element name="foo:A" namespace="FOO"> no invalidations reqired
// <xsl:attribute name="{}" namespace="FOO"> all prefixes should be invalidated but not default ""
// <xsl:attribute name="foo:A" namespace="{}"> all prefixes should be invalidated but not default ""
// <xsl:element name="foo:A" namespace="FOO"> We can try to invalidate only foo prefix, but there to many thinks to consider here.
// So for now if attribute has non-null namespace it invalidates all prefixes in the
// scope of its element.
//
// <xsl:copy-of select="@*|namespace::*"> all prefixes are invalidated for the current element scope
// <xsl:copy-of select="/|*|text()|etc."> no invalidations needed
// <xsl:copy> if the node is either attribute or namespace, all prefixes are invalidated for the current element scope
// if the node is element, new scope is created, and all prefixes are invalidated
// otherwise, no invalidations needed
//// We need following methods:
//public void InvalidatePrefix(string prefix) {
// Debug.Assert(prefix != null);
// if (LookupNamespace(prefix) == null) { // This is optimisation. May be better just add this record?
// return;
// }
// AddRecord(prefix, null);
//}
public void InvalidateAllPrefixes() {
if (records[lastRecord].prefix == null) {
return; // Averything was invalidated already. Nothing to do.
}
AddRecord(null, null);
}
public void InvalidateNonDefaultPrefixes() {
string defaultNs = LookupNamespace(string.Empty);
if (defaultNs == null) { // We don't know default NS anyway.
InvalidateAllPrefixes();
}
else {
if (
records[lastRecord ].prefix.Length == 0 &&
records[lastRecord - 1].prefix == null
) {
return; // Averything was already done
}
AddRecord(null, null);
AddRecord(string.Empty, defaultNs);
}
}
public string LookupNamespace(string prefix) {
Debug.Assert(prefix != null);
for (
int record = lastRecord; // from last record
records[record].prefix != null; // till lookup barrier
-- record // in reverce direction
) {
Debug.Assert(0 < record, "first record is lookup bariaer, so we don't need to check this condition runtime");
if (records[record].prefix == prefix) {
return records[record].nsUri;
}
}
return null;
}
}
}
|