1 using System;
2 using System.Collections;
3 using System.Text;
4
5
6
7
8
9 namespace System.Dom
10 {
11 public class Document : ParentNode
12 {
13 public suppress Document(const Document&);
14 public suppress Document(Document&&);
15 public Document() :
16 base(NodeType.documentNode, u"document"), documentElement(null), indexValid(false), xmlStandalone(false)
17 {
18 }
19 public suppress Document& operator=(const Document&);
20 public suppress Document& operator=(Document&&);
21 public Element* DocumentElement()
22 {
23 return documentElement;
24 }
25 public void SetXmlStandalone(bool xmlStandalone_)
26 {
27 xmlStandalone = xmlStandalone_;
28 }
29 public bool XmlStandalone() const
30 {
31 return xmlStandalone;
32 }
33 public void SetXmlVersion(const ustring& xmlVersion_)
34 {
35 xmlVersion = xmlVersion_;
36 }
37 public const ustring& XmlVersion() const
38 {
39 return xmlVersion;
40 }
41 public void SetXmlEncoding(const ustring& xmlEncoding_)
42 {
43 xmlEncoding = xmlEncoding_;
44 }
45 public const ustring& XmlEncoding() const
46 {
47 return xmlEncoding;
48 }
49 public void InternalInvalidateIndex()
50 {
51 indexValid = false;
52 }
53 public Element* GetElementById(const ustring& elementId)
54 {
55 if (!indexValid)
56 {
57 elementsByIdMap.Clear();
58 BuildIndexVisitor visitor(elementsByIdMap);
59 Accept(visitor);
60 indexValid = true;
61 }
62 HashMap<ustring, Element*>.ConstIterator it = elementsByIdMap.CFind(elementId);
63 if (it != elementsByIdMap.CEnd())
64 {
65 Element* element = it->second;
66 return element;
67 }
68 return null;
69 }
70 public void CheckValidInsert(Node* node, Node* refNode)
71 {
72 if (node->GetNodeType() == NodeType.elementNode)
73 {
74 if (refNode != null || documentElement != null)
75 {
76 throw DomException("attempt to insert a second element to a document");
77 }
78 }
79 }
80 public override void Write(CodeFormatter& formatter)
81 {
82 if (!xmlVersion.IsEmpty() && !xmlEncoding.IsEmpty())
83 {
84 formatter.WriteLine("<?xml version=\"" + ToUtf8(xmlVersion) + "\" encoding=\"" + ToUtf8(xmlEncoding) + "\"?>");
85 }
86 base->Write(formatter);
87 }
88 public override UniquePtr<Node> CloneNode(bool deep)
89 {
90 UniquePtr<Node> clonedDocument = UniquePtr<Node>(new Document());
91 if (deep)
92 {
93 ParentNode* parentNode = cast<ParentNode*>(clonedDocument.Get());
94 CloneChildrenTo(parentNode);
95 }
96 return clonedDocument;
97 }
98 public override Node* InsertBefore(UniquePtr<Node>&& newChild, Node* refChild)
99 {
100 CheckValidInsert(newChild.Get(), refChild);
101 if (newChild->GetNodeType() == NodeType.elementNode)
102 {
103 documentElement = cast<Element*>(newChild.Get());
104 }
105 return base->InsertBefore(Rvalue(newChild), refChild);
106 }
107 public override UniquePtr<Node> ReplaceChild(UniquePtr<Node>&& newChild, Node* oldChild)
108 {
109 if (!(oldChild != null))
110 {
111 throw DomException("could not replace node: given old child is null");
112 }
113 if (oldChild->Parent() != this)
114 {
115 throw DomException("could not replace node: given old child is not child of this node");
116 }
117 CheckValidInsert(newChild.Get(), null);
118 if (newChild->GetNodeType() == NodeType.elementNode)
119 {
120 UniquePtr<Node> removed = RemoveChild(oldChild);
121 AppendChild(Rvalue(newChild));
122 return removed;
123 }
124 else
125 {
126 return base->ReplaceChild(Rvalue(newChild), oldChild);
127 }
128 }
129 public override UniquePtr<Node> RemoveChild(Node* oldChild)
130 {
131 if (!(oldChild != null))
132 {
133 throw DomException("could not remove node: given old child is null");
134 }
135 if (oldChild->Parent() != this)
136 {
137 throw DomException("could not remove node: given old child is not child of this node");
138 }
139 if (oldChild->GetNodeType() == NodeType.elementNode)
140 {
141 documentElement = null;
142 }
143 return base->RemoveChild(oldChild);
144 }
145 public override Node* AppendChild(UniquePtr<Node>&& newChild)
146 {
147 CheckValidInsert(newChild.Get(), null);
148 if (newChild->GetNodeType() == NodeType.elementNode)
149 {
150 documentElement = cast<Element*>(newChild.Get());
151 }
152 return base->AppendChild(Rvalue(newChild));
153 }
154 public override void Accept(Visitor& visitor)
155 {
156 visitor.BeginVisit(this);
157 base->Accept(visitor);
158 visitor.EndVisit(this);
159 }
160 private Element* documentElement;
161 private HashMap<ustring, Element*> elementsByIdMap;
162 private bool indexValid;
163 private bool xmlStandalone;
164 private ustring xmlVersion;
165 private ustring xmlEncoding;
166 }
167 public class BuildIndexVisitor : Visitor
168 {
169 public BuildIndexVisitor(HashMap<ustring, Element*>& elementsByIdMap_) :
170 elementsByIdMap(elementsByIdMap_)
171 {
172 }
173 public override void BeginVisit(Element* element)
174 {
175 const ustring& id = element->GetAttribute(u"id");
176 if (!id.IsEmpty())
177 {
178 elementsByIdMap[id] = element;
179 }
180 }
181 private HashMap<ustring, Element*>& elementsByIdMap;
182 }
183 }