| File: System\Xml\Schema\SchemaInfo.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml) |
// 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.Collections.Generic; using System.Diagnostics; using System.Xml; namespace System.Xml.Schema { internal enum AttributeMatchState { AttributeFound, AnyIdAttributeFound, UndeclaredElementAndAttribute, UndeclaredAttribute, AnyAttributeLax, AnyAttributeSkip, ProhibitedAnyAttribute, ProhibitedAttribute, AttributeNameMismatch, ValidateAttributeInvalidCall, } internal sealed class SchemaInfo : IDtdInfo { private readonly Dictionary<XmlQualifiedName, SchemaElementDecl> _elementDecls = new Dictionary<XmlQualifiedName, SchemaElementDecl>(); private readonly Dictionary<XmlQualifiedName, SchemaElementDecl> _undeclaredElementDecls = new Dictionary<XmlQualifiedName, SchemaElementDecl>(); private Dictionary<XmlQualifiedName, SchemaEntity>? _generalEntities; private Dictionary<XmlQualifiedName, SchemaEntity>? _parameterEntities; private XmlQualifiedName _docTypeName = XmlQualifiedName.Empty; private string _internalDtdSubset = string.Empty; private bool _hasNonCDataAttributes; private bool _hasDefaultAttributes; private readonly Dictionary<string, bool> _targetNamespaces = new Dictionary<string, bool>(); private readonly Dictionary<XmlQualifiedName, SchemaAttDef> _attributeDecls = new Dictionary<XmlQualifiedName, SchemaAttDef>(); private int _errorCount; private SchemaType _schemaType; private readonly Dictionary<XmlQualifiedName, SchemaElementDecl> _elementDeclsByType = new Dictionary<XmlQualifiedName, SchemaElementDecl>(); private Dictionary<string, SchemaNotation>? _notations; internal SchemaInfo() { _schemaType = SchemaType.None; } public XmlQualifiedName DocTypeName { get { return _docTypeName; } set { _docTypeName = value; } } internal string InternalDtdSubset { get { return _internalDtdSubset; } set { _internalDtdSubset = value; } } internal Dictionary<XmlQualifiedName, SchemaElementDecl> ElementDecls { get { return _elementDecls; } } internal Dictionary<XmlQualifiedName, SchemaElementDecl> UndeclaredElementDecls { get { return _undeclaredElementDecls; } } internal Dictionary<XmlQualifiedName, SchemaEntity> GeneralEntities => _generalEntities ??= new Dictionary<XmlQualifiedName, SchemaEntity>(); internal Dictionary<XmlQualifiedName, SchemaEntity> ParameterEntities => _parameterEntities ??= new Dictionary<XmlQualifiedName, SchemaEntity>(); internal SchemaType SchemaType { get { return _schemaType; } set { _schemaType = value; } } internal Dictionary<string, bool> TargetNamespaces { get { return _targetNamespaces; } } internal Dictionary<XmlQualifiedName, SchemaElementDecl> ElementDeclsByType { get { return _elementDeclsByType; } } internal Dictionary<XmlQualifiedName, SchemaAttDef> AttributeDecls { get { return _attributeDecls; } } internal Dictionary<string, SchemaNotation> Notations => _notations ??= new Dictionary<string, SchemaNotation>(); internal int ErrorCount { get { return _errorCount; } set { _errorCount = value; } } internal SchemaElementDecl? GetElementDecl(XmlQualifiedName qname) { SchemaElementDecl? elemDecl; if (_elementDecls.TryGetValue(qname, out elemDecl)) { return elemDecl; } return null; } internal SchemaElementDecl? GetTypeDecl(XmlQualifiedName qname) { SchemaElementDecl? elemDecl; if (_elementDeclsByType.TryGetValue(qname, out elemDecl)) { return elemDecl; } return null; } internal XmlSchemaElement? GetElement(XmlQualifiedName qname) { SchemaElementDecl? ed = GetElementDecl(qname); if (ed != null) { return ed.SchemaElement; } return null; } internal bool HasSchema(string ns) { return _targetNamespaces.ContainsKey(ns); } internal bool Contains(string ns) { return _targetNamespaces.ContainsKey(ns); } internal SchemaAttDef? GetAttributeXdr(SchemaElementDecl? ed, XmlQualifiedName qname) { SchemaAttDef? attdef = null; if (ed != null) { attdef = ed.GetAttDef(qname); if (attdef == null) { if (!ed.ContentValidator!.IsOpen || qname.Namespace.Length == 0) { throw new XmlSchemaException(SR.Sch_UndeclaredAttribute, qname.ToString()); } if (!_attributeDecls.TryGetValue(qname, out attdef) && _targetNamespaces.ContainsKey(qname.Namespace)) { throw new XmlSchemaException(SR.Sch_UndeclaredAttribute, qname.ToString()); } } } return attdef; } internal SchemaAttDef? GetAttributeXsd(SchemaElementDecl? ed, XmlQualifiedName qname, XmlSchemaObject? partialValidationType, out AttributeMatchState attributeMatchState) { SchemaAttDef? attdef = null; attributeMatchState = AttributeMatchState.UndeclaredAttribute; if (ed != null) { attdef = ed.GetAttDef(qname); if (attdef != null) { attributeMatchState = AttributeMatchState.AttributeFound; return attdef; } XmlSchemaAnyAttribute? any = ed.AnyAttribute; if (any != null) { if (!any.NamespaceList!.Allows(qname)) { attributeMatchState = AttributeMatchState.ProhibitedAnyAttribute; } else if (any.ProcessContentsCorrect != XmlSchemaContentProcessing.Skip) { if (_attributeDecls.TryGetValue(qname, out attdef)) { if (attdef.Datatype.TypeCode == XmlTypeCode.Id) { //anyAttribute match whose type is ID attributeMatchState = AttributeMatchState.AnyIdAttributeFound; } else { attributeMatchState = AttributeMatchState.AttributeFound; } } else if (any.ProcessContentsCorrect == XmlSchemaContentProcessing.Lax) { attributeMatchState = AttributeMatchState.AnyAttributeLax; } } else { attributeMatchState = AttributeMatchState.AnyAttributeSkip; } } else if (ed.ProhibitedAttributes.ContainsKey(qname)) { attributeMatchState = AttributeMatchState.ProhibitedAttribute; } } else if (partialValidationType != null) { XmlSchemaAttribute? attr = partialValidationType as XmlSchemaAttribute; if (attr != null) { if (qname.Equals(attr.QualifiedName)) { attdef = attr.AttDef; attributeMatchState = AttributeMatchState.AttributeFound; } else { attributeMatchState = AttributeMatchState.AttributeNameMismatch; } } else { attributeMatchState = AttributeMatchState.ValidateAttributeInvalidCall; } } else { if (_attributeDecls.TryGetValue(qname, out attdef)) { attributeMatchState = AttributeMatchState.AttributeFound; } else { attributeMatchState = AttributeMatchState.UndeclaredElementAndAttribute; } } return attdef; } internal SchemaAttDef? GetAttributeXsd(SchemaElementDecl? ed, XmlQualifiedName qname, ref bool skip) { AttributeMatchState attributeMatchState; SchemaAttDef? attDef = GetAttributeXsd(ed, qname, null, out attributeMatchState); switch (attributeMatchState) { case AttributeMatchState.UndeclaredAttribute: throw new XmlSchemaException(SR.Sch_UndeclaredAttribute, qname.ToString()); case AttributeMatchState.ProhibitedAnyAttribute: case AttributeMatchState.ProhibitedAttribute: throw new XmlSchemaException(SR.Sch_ProhibitedAttribute, qname.ToString()); case AttributeMatchState.AttributeFound: case AttributeMatchState.AnyIdAttributeFound: case AttributeMatchState.AnyAttributeLax: case AttributeMatchState.UndeclaredElementAndAttribute: break; case AttributeMatchState.AnyAttributeSkip: skip = true; break; default: Debug.Fail($"Unexpected match state {attributeMatchState}"); break; } return attDef; } internal void Add(SchemaInfo sinfo, ValidationEventHandler? eventhandler) { if (_schemaType == SchemaType.None) { _schemaType = sinfo.SchemaType; } else if (_schemaType != sinfo.SchemaType) { eventhandler?.Invoke(this, new ValidationEventArgs(new XmlSchemaException(SR.Sch_MixSchemaTypes, string.Empty))); return; } foreach (string tns in sinfo.TargetNamespaces.Keys) { _targetNamespaces.TryAdd(tns, true); } foreach (KeyValuePair<XmlQualifiedName, SchemaElementDecl> entry in sinfo._elementDecls) { if (!_elementDecls.ContainsKey(entry.Key)) { _elementDecls.Add(entry.Key, entry.Value); } } foreach (KeyValuePair<XmlQualifiedName, SchemaElementDecl> entry in sinfo._elementDeclsByType) { if (!_elementDeclsByType.ContainsKey(entry.Key)) { _elementDeclsByType.Add(entry.Key, entry.Value); } } foreach (SchemaAttDef attdef in sinfo.AttributeDecls.Values) { _attributeDecls.TryAdd(attdef.Name, attdef); } foreach (SchemaNotation notation in sinfo.Notations.Values) { Notations.TryAdd(notation.Name.Name, notation); } } internal void Finish() { Dictionary<XmlQualifiedName, SchemaElementDecl> elements = _elementDecls; for (int i = 0; i < 2; i++) { foreach (SchemaElementDecl e in elements.Values) { if (e.HasNonCDataAttribute) { _hasNonCDataAttributes = true; } if (e.DefaultAttDefs != null) { _hasDefaultAttributes = true; } } elements = _undeclaredElementDecls; } } // // IDtdInfo interface // #region IDtdInfo Members bool IDtdInfo.HasDefaultAttributes { get { return _hasDefaultAttributes; } } bool IDtdInfo.HasNonCDataAttributes { get { return _hasNonCDataAttributes; } } IDtdAttributeListInfo? IDtdInfo.LookupAttributeList(string prefix, string localName) { XmlQualifiedName qname = new XmlQualifiedName(prefix, localName); SchemaElementDecl? elementDecl; if (!_elementDecls.TryGetValue(qname, out elementDecl)) { _undeclaredElementDecls.TryGetValue(qname, out elementDecl); } return elementDecl; } IEnumerable<IDtdAttributeListInfo> IDtdInfo.GetAttributeLists() { foreach (SchemaElementDecl elemDecl in _elementDecls.Values) { IDtdAttributeListInfo eleDeclAsAttList = (IDtdAttributeListInfo)elemDecl; yield return eleDeclAsAttList; } } IDtdEntityInfo? IDtdInfo.LookupEntity(string name) { if (_generalEntities == null) { return null; } XmlQualifiedName qname = new XmlQualifiedName(name); SchemaEntity? entity; if (_generalEntities.TryGetValue(qname, out entity)) { return entity; } return null; } XmlQualifiedName IDtdInfo.Name { get { return _docTypeName; } } string IDtdInfo.InternalDtdSubset { get { return _internalDtdSubset; } } #endregion } }