|
//------------------------------------------------------------------------------
// <copyright file="NamespaceList.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
namespace System.Xml.Schema {
using System.Collections;
using System.Text;
using System.Diagnostics;
internal class NamespaceList {
public enum ListType {
Any,
Other,
Set
};
private ListType type = ListType.Any;
private Hashtable set = null;
private string targetNamespace;
public NamespaceList() {
}
public NamespaceList(string namespaces, string targetNamespace) {
Debug.Assert(targetNamespace != null);
this.targetNamespace = targetNamespace;
namespaces = namespaces.Trim();
if (namespaces == "##any" || namespaces.Length == 0) {
type = ListType.Any;
}
else if (namespaces == "##other") {
type = ListType.Other;
}
else {
type = ListType.Set;
set = new Hashtable();
string[] splitString = XmlConvert.SplitString(namespaces);
for (int i = 0; i < splitString.Length; ++i) {
if (splitString[i] == "##local") {
set[string.Empty] = string.Empty;
}
else if (splitString[i] == "##targetNamespace") {
set[targetNamespace] = targetNamespace;
}
else {
XmlConvert.ToUri (splitString[i]); // can throw
set[splitString[i]] = splitString[i];
}
}
}
}
public NamespaceList Clone() {
NamespaceList nsl = (NamespaceList)MemberwiseClone();
if (type == ListType.Set) {
Debug.Assert(set != null);
nsl.set = (Hashtable)(set.Clone());
}
return nsl;
}
public ListType Type {
get { return type; }
}
public string Excluded {
get { return targetNamespace; }
}
public ICollection Enumerate {
get {
switch (type) {
case ListType.Set:
return set.Keys;
case ListType.Other:
case ListType.Any:
default:
throw new InvalidOperationException();
}
}
}
public virtual bool Allows(string ns) {
switch (type) {
case ListType.Any:
return true;
case ListType.Other:
return ns != targetNamespace && ns.Length != 0;
case ListType.Set:
return set[ns] != null;
}
Debug.Assert(false);
return false;
}
public bool Allows(XmlQualifiedName qname) {
return Allows(qname.Namespace);
}
public override string ToString() {
switch (type) {
case ListType.Any:
return "##any";
case ListType.Other:
return "##other";
case ListType.Set:
StringBuilder sb = new StringBuilder();
bool first = true;
foreach(string s in set.Keys) {
if (first) {
first = false;
}
else {
sb.Append(" ");
}
if (s == targetNamespace) {
sb.Append("##targetNamespace");
}
else if (s.Length == 0) {
sb.Append("##local");
}
else {
sb.Append(s);
}
}
return sb.ToString();
}
Debug.Assert(false);
return string.Empty;
}
public static bool IsSubset(NamespaceList sub, NamespaceList super) {
if (super.type == ListType.Any) {
return true;
}
else if (sub.type == ListType.Other && super.type == ListType.Other) {
return super.targetNamespace == sub.targetNamespace;
}
else if (sub.type == ListType.Set) {
if (super.type == ListType.Other) {
return !sub.set.Contains(super.targetNamespace);
}
else {
Debug.Assert(super.type == ListType.Set);
foreach (string ns in sub.set.Keys) {
if (!super.set.Contains(ns)) {
return false;
}
}
return true;
}
}
return false;
}
public static NamespaceList Union(NamespaceList o1, NamespaceList o2, bool v1Compat) {
NamespaceList nslist = null;
Debug.Assert(o1 != o2);
if (o1.type == ListType.Any) { //clause 2 - o1 is Any
nslist = new NamespaceList();
}
else if (o2.type == ListType.Any) { //clause 2 - o2 is Any
nslist = new NamespaceList();
}
else if (o1.type == ListType.Set && o2.type == ListType.Set) { //clause 3 , both are sets
nslist = o1.Clone();
foreach (string ns in o2.set.Keys) {
nslist.set[ns] = ns;
}
}
else if (o1.type == ListType.Other && o2.type == ListType.Other) { //clause 4, both are negations
if (o1.targetNamespace == o2.targetNamespace) { //negation of same value
nslist = o1.Clone();
}
else { //Not a breaking change, going from not expressible to not(absent)
nslist = new NamespaceList("##other", string.Empty); //clause 4, negations of different values, result is not(absent)
}
}
else if (o1.type == ListType.Set && o2.type == ListType.Other) {
if (v1Compat) {
if (o1.set.Contains(o2.targetNamespace)) {
nslist = new NamespaceList();
}
else { //This was not there originally in V1, added for consistency since its not breaking
nslist = o2.Clone();
}
}
else {
if (o2.targetNamespace != string.Empty) { //clause 5, o1 is set S, o2 is not(tns)
nslist = o1.CompareSetToOther(o2);
}
else if (o1.set.Contains(string.Empty)) { //clause 6.1 - set S includes absent, o2 is not(absent)
nslist = new NamespaceList();
}
else { //clause 6.2 - set S does not include absent, result is not(absent)
nslist = new NamespaceList("##other", string.Empty);
}
}
}
else if (o2.type == ListType.Set && o1.type == ListType.Other) {
if (v1Compat) {
if (o2.set.Contains(o2.targetNamespace)) {
nslist = new NamespaceList();
}
else {
nslist = o1.Clone();
}
}
else { //New rules
if (o1.targetNamespace != string.Empty) { //clause 5, o1 is set S, o2 is not(tns)
nslist = o2.CompareSetToOther(o1);
}
else if (o2.set.Contains(string.Empty)) { //clause 6.1 - set S includes absent, o2 is not(absent)
nslist = new NamespaceList();
}
else { //clause 6.2 - set S does not include absent, result is not(absent)
nslist = new NamespaceList("##other", string.Empty);
}
}
}
return nslist;
}
private NamespaceList CompareSetToOther(NamespaceList other) {
//clause 5.1
NamespaceList nslist = null;
if (this.set.Contains(other.targetNamespace)) { //S contains negated ns
if (this.set.Contains(string.Empty)) { // AND S contains absent
nslist = new NamespaceList(); //any is the result
}
else { //clause 5.2
nslist = new NamespaceList("##other", string.Empty);
}
}
else if (this.set.Contains(string.Empty)) { //clause 5.3 - Not expressible
nslist = null;
}
else { //clause 5.4 - Set S does not contain negated ns or absent
nslist = other.Clone();
}
return nslist;
}
public static NamespaceList Intersection(NamespaceList o1, NamespaceList o2, bool v1Compat) {
NamespaceList nslist = null;
Debug.Assert(o1 != o2); //clause 1
if (o1.type == ListType.Any) { //clause 2 - o1 is any
nslist = o2.Clone();
}
else if (o2.type == ListType.Any) { //clause 2 - o2 is any
nslist = o1.Clone();
}
else if (o1.type == ListType.Set && o2.type == ListType.Other) { //Clause 3 o2 is other
nslist = o1.Clone();
nslist.RemoveNamespace(o2.targetNamespace);
if (!v1Compat) {
nslist.RemoveNamespace(string.Empty); //remove ##local
}
}
else if (o1.type == ListType.Other && o2.type == ListType.Set) { //Clause 3 o1 is other
nslist = o2.Clone();
nslist.RemoveNamespace(o1.targetNamespace);
if (!v1Compat) {
nslist.RemoveNamespace(string.Empty); //remove ##local
}
}
else if (o1.type == ListType.Set && o2.type == ListType.Set) { //clause 4
nslist = o1.Clone();
nslist = new NamespaceList();
nslist.type = ListType.Set;
nslist.set = new Hashtable();
foreach(string ns in o1.set.Keys) {
if (o2.set.Contains(ns)) {
nslist.set.Add(ns, ns);
}
}
}
else if (o1.type == ListType.Other && o2.type == ListType.Other) {
if (o1.targetNamespace == o2.targetNamespace) { //negation of same namespace name
nslist = o1.Clone();
return nslist;
}
if (!v1Compat) {
if (o1.targetNamespace == string.Empty) { // clause 6 - o1 is negation of absent
nslist = o2.Clone();
}
else if (o2.targetNamespace == string.Empty) { //clause 6 - o1 is negation of absent
nslist = o1.Clone();
}
}
//if it comes here, its not expressible //clause 5
}
return nslist;
}
private void RemoveNamespace(string tns) {
if (this.set[tns] != null) {
this.set.Remove(tns);
}
}
public bool IsEmpty() {
return ((type == ListType.Set) && ((set == null) || set.Count == 0));
}
};
internal class NamespaceListV1Compat : NamespaceList {
public NamespaceListV1Compat(string namespaces, string targetNamespace) : base(namespaces, targetNamespace) {}
public override bool Allows(string ns) {
if (this.Type == ListType.Other) {
return ns != Excluded;
}
else {
return base.Allows(ns);
}
}
}
}
|