| File: System\Xml\Dom\XmlEntityReference.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.Diagnostics; namespace System.Xml { // Represents an entity reference node. // <code>EntityReference</code> objects may be inserted into the structure // model when an entity reference is in the source document, or when the user // wishes to insert an entity reference. Note that character references and // references to predefined entities are considered to be expanded by the // HTML or XML processor so that characters are represented by their Unicode // equivalent rather than by an entity reference. Moreover, the XML // processor may completely expand references to entities while building the // structure model, instead of providing <code>EntityReference</code> // objects. If it does provide such objects, then for a given // <code>EntityReference</code> node, it may be that there is no // <code>Entity</code> node representing the referenced entity; but if such // an <code>Entity</code> exists, then the child list of the // <code>EntityReference</code> node is the same as that of the // <code>Entity</code> node. As with the <code>Entity</code> node, all // descendants of the <code>EntityReference</code> are readonly. // <p>The resolution of the children of the <code>EntityReference</code> (the // replacement value of the referenced <code>Entity</code>) may be lazily // evaluated; actions by the user (such as calling the // <code>childNodes</code> method on the <code>EntityReference</code> node) // are assumed to trigger the evaluation. public class XmlEntityReference : XmlLinkedNode { private readonly string _name; private XmlLinkedNode? _lastChild; protected internal XmlEntityReference(string name, XmlDocument doc) : base(doc) { if (!doc.IsLoading) { if (name.StartsWith('#')) { throw new ArgumentException(SR.Xdom_InvalidCharacter_EntityReference); } } _name = doc.NameTable.Add(name); doc.fEntRefNodesPresent = true; } // Gets the name of the node. public override string Name { get { return _name; } } // Gets the name of the node without the namespace prefix. public override string LocalName { get { return _name; } } // Gets or sets the value of the node. public override string? Value { get { return null; } set { throw new InvalidOperationException(SR.Xdom_EntRef_SetVal); } } // Gets the type of the node. public override XmlNodeType NodeType { get { return XmlNodeType.EntityReference; } } // Creates a duplicate of this node. public override XmlNode CloneNode(bool deep) { Debug.Assert(OwnerDocument != null); XmlEntityReference eref = OwnerDocument.CreateEntityReference(_name); return eref; } // // Microsoft extensions // // Gets a value indicating whether the node is read-only. public override bool IsReadOnly { get { return true; // Make entity references readonly } } internal override bool IsContainer { get { return true; } } internal override void SetParent(XmlNode? node) { base.SetParent(node); if (LastNode == null && node != null && node != OwnerDocument) { //first time insert the entity reference into the tree, we should expand its children now XmlLoader loader = new XmlLoader(); loader.ExpandEntityReference(this); } } internal override void SetParentForLoad(XmlNode node) { this.SetParent(node); } internal override XmlLinkedNode? LastNode { get { return _lastChild; } set { _lastChild = value; } } internal override bool IsValidChildType(XmlNodeType type) { switch (type) { case XmlNodeType.Element: case XmlNodeType.Text: case XmlNodeType.EntityReference: case XmlNodeType.Comment: case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: case XmlNodeType.ProcessingInstruction: case XmlNodeType.CDATA: return true; default: return false; } } // Saves the node to the specified XmlWriter. public override void WriteTo(XmlWriter w) { w.WriteEntityRef(_name); } // Saves all the children of the node to the specified XmlWriter. public override void WriteContentTo(XmlWriter w) { // -- eventually will the fix. commented out waiting for finalizing on the issue. foreach (XmlNode n in this) { n.WriteTo(w); } //still use the old code to generate the output /* foreach ( XmlNode n in this ) { if ( n.NodeType != XmlNodeType.EntityReference ) n.WriteTo( w ); else n.WriteContentTo( w ); }*/ } public override string BaseURI { get { return OwnerDocument!.BaseURI; } } private static string ConstructBaseURI(string baseURI, string systemId) { if (baseURI == null) return systemId; int nCount = baseURI.LastIndexOf('/') + 1; string buf = baseURI; if (nCount > 0 && nCount < baseURI.Length) buf = baseURI.Substring(0, nCount); else if (nCount == 0) buf = $"{buf}\\"; return string.Create(buf.Length + systemId.Length, (buf, systemId), (dest, state) => { state.buf.CopyTo(dest); state.systemId.AsSpan().Replace(dest.Slice(state.buf.Length), '\\', '/'); }); } //childrenBaseURI returns where the entity reference node's children come from internal string ChildBaseURI { get { //get the associate entity and return its baseUri XmlEntity? ent = OwnerDocument!.GetEntityNode(_name); if (ent != null) { if (!string.IsNullOrEmpty(ent.SystemId)) return ConstructBaseURI(ent.BaseURI, ent.SystemId); else return ent.BaseURI; } return string.Empty; } } } }