|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 * nsIContentSerializer implementation that can be used with an |
|
8 * nsIDocumentEncoder to convert an XML DOM to an XML string that |
|
9 * could be parsed into more or less the original DOM. |
|
10 */ |
|
11 |
|
12 #ifndef nsXMLContentSerializer_h__ |
|
13 #define nsXMLContentSerializer_h__ |
|
14 |
|
15 #include "mozilla/Attributes.h" |
|
16 #include "nsIContentSerializer.h" |
|
17 #include "nsISupportsUtils.h" |
|
18 #include "nsCOMPtr.h" |
|
19 #include "nsTArray.h" |
|
20 #include "nsString.h" |
|
21 |
|
22 #define kIndentStr NS_LITERAL_STRING(" ") |
|
23 #define kEndTag NS_LITERAL_STRING("</") |
|
24 |
|
25 class nsIAtom; |
|
26 class nsIDOMNode; |
|
27 class nsINode; |
|
28 |
|
29 class nsXMLContentSerializer : public nsIContentSerializer { |
|
30 public: |
|
31 nsXMLContentSerializer(); |
|
32 virtual ~nsXMLContentSerializer(); |
|
33 |
|
34 NS_DECL_ISUPPORTS |
|
35 |
|
36 NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn, |
|
37 const char* aCharSet, bool aIsCopying, |
|
38 bool aRewriteEncodingDeclaration) MOZ_OVERRIDE; |
|
39 |
|
40 NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset, |
|
41 int32_t aEndOffset, nsAString& aStr) MOZ_OVERRIDE; |
|
42 |
|
43 NS_IMETHOD AppendCDATASection(nsIContent* aCDATASection, |
|
44 int32_t aStartOffset, int32_t aEndOffset, |
|
45 nsAString& aStr) MOZ_OVERRIDE; |
|
46 |
|
47 NS_IMETHOD AppendProcessingInstruction(nsIContent* aPI, |
|
48 int32_t aStartOffset, |
|
49 int32_t aEndOffset, |
|
50 nsAString& aStr) MOZ_OVERRIDE; |
|
51 |
|
52 NS_IMETHOD AppendComment(nsIContent* aComment, int32_t aStartOffset, |
|
53 int32_t aEndOffset, nsAString& aStr) MOZ_OVERRIDE; |
|
54 |
|
55 NS_IMETHOD AppendDoctype(nsIContent *aDoctype, |
|
56 nsAString& aStr) MOZ_OVERRIDE; |
|
57 |
|
58 NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement, |
|
59 mozilla::dom::Element* aOriginalElement, |
|
60 nsAString& aStr) MOZ_OVERRIDE; |
|
61 |
|
62 NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement, |
|
63 nsAString& aStr) MOZ_OVERRIDE; |
|
64 |
|
65 NS_IMETHOD Flush(nsAString& aStr) MOZ_OVERRIDE { return NS_OK; } |
|
66 |
|
67 NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument, |
|
68 nsAString& aStr) MOZ_OVERRIDE; |
|
69 |
|
70 protected: |
|
71 |
|
72 /** |
|
73 * Appends a char16_t character and increments the column position |
|
74 */ |
|
75 void AppendToString(const char16_t aChar, |
|
76 nsAString& aOutputStr); |
|
77 |
|
78 /** |
|
79 * Appends a nsAString string and increments the column position |
|
80 */ |
|
81 void AppendToString(const nsAString& aStr, |
|
82 nsAString& aOutputStr); |
|
83 |
|
84 /** |
|
85 * Appends a string by replacing all line-endings |
|
86 * by mLineBreak, except in the case of raw output. |
|
87 * It increments the column position. |
|
88 */ |
|
89 void AppendToStringConvertLF(const nsAString& aStr, |
|
90 nsAString& aOutputStr); |
|
91 |
|
92 /** |
|
93 * Appends a string by wrapping it when necessary. |
|
94 * It updates the column position. |
|
95 */ |
|
96 void AppendToStringWrapped(const nsASingleFragmentString& aStr, |
|
97 nsAString& aOutputStr); |
|
98 |
|
99 /** |
|
100 * Appends a string by formating and wrapping it when necessary |
|
101 * It updates the column position. |
|
102 */ |
|
103 void AppendToStringFormatedWrapped(const nsASingleFragmentString& aStr, |
|
104 nsAString& aOutputStr); |
|
105 |
|
106 // used by AppendToStringWrapped |
|
107 void AppendWrapped_WhitespaceSequence( |
|
108 nsASingleFragmentString::const_char_iterator &aPos, |
|
109 const nsASingleFragmentString::const_char_iterator aEnd, |
|
110 const nsASingleFragmentString::const_char_iterator aSequenceStart, |
|
111 nsAString &aOutputStr); |
|
112 |
|
113 // used by AppendToStringFormatedWrapped |
|
114 void AppendFormatedWrapped_WhitespaceSequence( |
|
115 nsASingleFragmentString::const_char_iterator &aPos, |
|
116 const nsASingleFragmentString::const_char_iterator aEnd, |
|
117 const nsASingleFragmentString::const_char_iterator aSequenceStart, |
|
118 bool &aMayIgnoreStartOfLineWhitespaceSequence, |
|
119 nsAString &aOutputStr); |
|
120 |
|
121 // used by AppendToStringWrapped and AppendToStringFormatedWrapped |
|
122 void AppendWrapped_NonWhitespaceSequence( |
|
123 nsASingleFragmentString::const_char_iterator &aPos, |
|
124 const nsASingleFragmentString::const_char_iterator aEnd, |
|
125 const nsASingleFragmentString::const_char_iterator aSequenceStart, |
|
126 bool &aMayIgnoreStartOfLineWhitespaceSequence, |
|
127 bool &aSequenceStartAfterAWhiteSpace, |
|
128 nsAString &aOutputStr); |
|
129 |
|
130 /** |
|
131 * add mLineBreak to the string |
|
132 * It updates the column position and other flags. |
|
133 */ |
|
134 void AppendNewLineToString(nsAString& aOutputStr); |
|
135 |
|
136 |
|
137 /** |
|
138 * Appends a string by translating entities |
|
139 * It doesn't increment the column position |
|
140 */ |
|
141 virtual void AppendAndTranslateEntities(const nsAString& aStr, |
|
142 nsAString& aOutputStr); |
|
143 |
|
144 /** |
|
145 * retrieve the text content of the node and append it to the given string |
|
146 * It doesn't increment the column position |
|
147 */ |
|
148 nsresult AppendTextData(nsIContent* aNode, |
|
149 int32_t aStartOffset, |
|
150 int32_t aEndOffset, |
|
151 nsAString& aStr, |
|
152 bool aTranslateEntities); |
|
153 |
|
154 virtual nsresult PushNameSpaceDecl(const nsAString& aPrefix, |
|
155 const nsAString& aURI, |
|
156 nsIContent* aOwner); |
|
157 void PopNameSpaceDeclsFor(nsIContent* aOwner); |
|
158 |
|
159 /** |
|
160 * The problem that ConfirmPrefix fixes is that anyone can insert nodes |
|
161 * through the DOM that have a namespace URI and a random or empty or |
|
162 * previously existing prefix that's totally unrelated to the prefixes |
|
163 * declared at that point through xmlns attributes. So what ConfirmPrefix |
|
164 * does is ensure that we can map aPrefix to the namespace URI aURI (for |
|
165 * example, that the prefix is not already mapped to some other namespace). |
|
166 * aPrefix will be adjusted, if necessary, so the value of the prefix |
|
167 * _after_ this call is what should be serialized. |
|
168 * @param aPrefix the prefix that may need adjusting |
|
169 * @param aURI the namespace URI we want aPrefix to point to |
|
170 * @param aElement the element we're working with (needed for proper default |
|
171 * namespace handling) |
|
172 * @param aIsAttribute true if we're confirming a prefix for an attribute. |
|
173 * @return true if we need to push the (prefix, uri) pair on the namespace |
|
174 * stack (note that this can happen even if the prefix is |
|
175 * empty). |
|
176 */ |
|
177 bool ConfirmPrefix(nsAString& aPrefix, |
|
178 const nsAString& aURI, |
|
179 nsIContent* aElement, |
|
180 bool aIsAttribute); |
|
181 /** |
|
182 * GenerateNewPrefix generates a new prefix and writes it to aPrefix |
|
183 */ |
|
184 void GenerateNewPrefix(nsAString& aPrefix); |
|
185 |
|
186 uint32_t ScanNamespaceDeclarations(nsIContent* aContent, |
|
187 nsIContent *aOriginalElement, |
|
188 const nsAString& aTagNamespaceURI); |
|
189 |
|
190 virtual void SerializeAttributes(nsIContent* aContent, |
|
191 nsIContent *aOriginalElement, |
|
192 nsAString& aTagPrefix, |
|
193 const nsAString& aTagNamespaceURI, |
|
194 nsIAtom* aTagName, |
|
195 nsAString& aStr, |
|
196 uint32_t aSkipAttr, |
|
197 bool aAddNSAttr); |
|
198 |
|
199 void SerializeAttr(const nsAString& aPrefix, |
|
200 const nsAString& aName, |
|
201 const nsAString& aValue, |
|
202 nsAString& aStr, |
|
203 bool aDoEscapeEntities); |
|
204 |
|
205 bool IsJavaScript(nsIContent * aContent, |
|
206 nsIAtom* aAttrNameAtom, |
|
207 int32_t aAttrNamespaceID, |
|
208 const nsAString& aValueString); |
|
209 |
|
210 /** |
|
211 * This method can be redefined to check if the element can be serialized. |
|
212 * It is called when the serialization of the start tag is asked |
|
213 * (AppendElementStart) |
|
214 * In this method you can also force the formating |
|
215 * by setting aForceFormat to true. |
|
216 * @return boolean true if the element can be output |
|
217 */ |
|
218 virtual bool CheckElementStart(nsIContent * aContent, |
|
219 bool & aForceFormat, |
|
220 nsAString& aStr); |
|
221 |
|
222 /** |
|
223 * this method is responsible to finish the start tag, |
|
224 * in particulary to append the "greater than" sign |
|
225 */ |
|
226 virtual void AppendEndOfElementStart(nsIContent *aOriginalElement, |
|
227 nsIAtom * aName, |
|
228 int32_t aNamespaceID, |
|
229 nsAString& aStr); |
|
230 |
|
231 /** |
|
232 * This method can be redefine to serialize additional things just after |
|
233 * after the serialization ot the start tag. |
|
234 * (called at the end of AppendElementStart) |
|
235 */ |
|
236 virtual void AfterElementStart(nsIContent * aContent, |
|
237 nsIContent *aOriginalElement, |
|
238 nsAString& aStr) { }; |
|
239 |
|
240 /** |
|
241 * This method can be redefined to check if the element can be serialized. |
|
242 * It is called when the serialization of the end tag is asked |
|
243 * (AppendElementEnd) |
|
244 * In this method you can also force the formating |
|
245 * by setting aForceFormat to true. |
|
246 * @return boolean true if the element can be output |
|
247 */ |
|
248 virtual bool CheckElementEnd(nsIContent * aContent, |
|
249 bool & aForceFormat, |
|
250 nsAString& aStr); |
|
251 |
|
252 /** |
|
253 * This method can be redefine to serialize additional things just after |
|
254 * after the serialization ot the end tag. |
|
255 * (called at the end of AppendElementStart) |
|
256 */ |
|
257 virtual void AfterElementEnd(nsIContent * aContent, |
|
258 nsAString& aStr) { }; |
|
259 |
|
260 /** |
|
261 * Returns true if a line break should be inserted before an element open tag |
|
262 */ |
|
263 virtual bool LineBreakBeforeOpen(int32_t aNamespaceID, nsIAtom* aName); |
|
264 |
|
265 /** |
|
266 * Returns true if a line break should be inserted after an element open tag |
|
267 */ |
|
268 virtual bool LineBreakAfterOpen(int32_t aNamespaceID, nsIAtom* aName); |
|
269 |
|
270 /** |
|
271 * Returns true if a line break should be inserted after an element close tag |
|
272 */ |
|
273 virtual bool LineBreakBeforeClose(int32_t aNamespaceID, nsIAtom* aName); |
|
274 |
|
275 /** |
|
276 * Returns true if a line break should be inserted after an element close tag |
|
277 */ |
|
278 virtual bool LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aName); |
|
279 |
|
280 /** |
|
281 * add intendation. Call only in the case of formating and if the current |
|
282 * position is at 0. It updates the column position. |
|
283 */ |
|
284 void AppendIndentation(nsAString& aStr); |
|
285 void IncrIndentation(nsIAtom* aName); |
|
286 void DecrIndentation(nsIAtom* aName); |
|
287 |
|
288 // Functions to check for newlines that needs to be added between nodes in |
|
289 // the root of a document. See mAddNewlineForRootNode |
|
290 void MaybeAddNewlineForRootNode(nsAString& aStr); |
|
291 void MaybeFlagNewlineForRootNode(nsINode* aNode); |
|
292 |
|
293 // Functions to check if we enter in or leave from a preformated content |
|
294 virtual void MaybeEnterInPreContent(nsIContent* aNode); |
|
295 virtual void MaybeLeaveFromPreContent(nsIContent* aNode); |
|
296 |
|
297 int32_t mPrefixIndex; |
|
298 |
|
299 struct NameSpaceDecl { |
|
300 nsString mPrefix; |
|
301 nsString mURI; |
|
302 nsIContent* mOwner; |
|
303 }; |
|
304 |
|
305 nsTArray<NameSpaceDecl> mNameSpaceStack; |
|
306 |
|
307 // nsIDocumentEncoder flags |
|
308 uint32_t mFlags; |
|
309 |
|
310 // characters to use for line break |
|
311 nsString mLineBreak; |
|
312 |
|
313 // The charset that was passed to Init() |
|
314 nsCString mCharset; |
|
315 |
|
316 // current column position on the current line |
|
317 uint32_t mColPos; |
|
318 |
|
319 // true = pretty formating should be done (OutputFormated flag) |
|
320 bool mDoFormat; |
|
321 |
|
322 // true = no formatting,(OutputRaw flag) |
|
323 // no newline convertion and no rewrap long lines even if OutputWrap is set. |
|
324 bool mDoRaw; |
|
325 |
|
326 // true = wrapping should be done (OutputWrap flag) |
|
327 bool mDoWrap; |
|
328 |
|
329 // number of maximum column in a line, in the wrap mode |
|
330 uint32_t mMaxColumn; |
|
331 |
|
332 // current indent value |
|
333 nsString mIndent; |
|
334 |
|
335 // this is the indentation level after the indentation reached |
|
336 // the maximum length of indentation |
|
337 int32_t mIndentOverflow; |
|
338 |
|
339 // says if the indentation has been already added on the current line |
|
340 bool mIsIndentationAddedOnCurrentLine; |
|
341 |
|
342 // the string which is currently added is in an attribute |
|
343 bool mInAttribute; |
|
344 |
|
345 // true = a newline character should be added. It's only |
|
346 // useful when serializing root nodes. see MaybeAddNewlineForRootNode and |
|
347 // MaybeFlagNewlineForRootNode |
|
348 bool mAddNewlineForRootNode; |
|
349 |
|
350 // Indicates that a space will be added if and only if content is |
|
351 // continued on the same line while serializing source. Otherwise, |
|
352 // the newline character acts as the whitespace and no space is needed. |
|
353 // used when mDoFormat = true |
|
354 bool mAddSpace; |
|
355 |
|
356 // says that if the next string to add contains a newline character at the |
|
357 // begining, then this newline character should be ignored, because a |
|
358 // such character has already been added into the output string |
|
359 bool mMayIgnoreLineBreakSequence; |
|
360 |
|
361 bool mBodyOnly; |
|
362 int32_t mInBody; |
|
363 |
|
364 // number of nested elements which have preformated content |
|
365 int32_t mPreLevel; |
|
366 }; |
|
367 |
|
368 nsresult |
|
369 NS_NewXMLContentSerializer(nsIContentSerializer** aSerializer); |
|
370 |
|
371 #endif |