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