Xalan-C++ API Reference 1.12.0
FormatterToXMLUnicode.hpp
Go to the documentation of this file.
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18#if !defined(FORMATTERTOXML_UNICODE_HEADER_GUARD_1357924680)
19#define FORMATTERTOXML_UNICODE_HEADER_GUARD_1357924680
20
21
22// Base include file. Must be first.
24
25
26
28
29
30
31#include "xercesc/sax/AttributeList.hpp"
32
33
34
38
39
40
42
43
44
45namespace XALAN_CPP_NAMESPACE {
46
47
48/**
49 * FormatterToXMLUnicode formats SAX-style events into XML.
50 */
51template<
52 class UnicodeWriter,
53 class ConstantsType,
54 class CharPredicate,
55 class IndentHandler,
56 FormatterListener::eXMLVersion XMLVersion>
58{
59public:
60
61 typedef typename UnicodeWriter::value_type value_type;
62
63 enum
64 {
65 eDefaultIndentAmount = 0
66 };
67
68 /**
69 * Constructor
70 *
71 * @param theManager The MemoryManager instance to use for all memory allocations
72 * @param writer the writer.
73 * @param version the string to write for the XML version number.
74 * @param doctypeSystem system identifier to be used in the document
75 * type declaration
76 * @param doctypePublic public identifier to be used in the document
77 * type declaration
78 * @param xmlDecl true if the XSLT processor should output an XML
79 * declaration
80 * @param standalone The string the XSLT processor should output for
81 * the standalone document declaration
82 *
83 */
85 MemoryManager& theManager,
88 const XalanDOMString& doctypeSystem = s_emptyString,
89 const XalanDOMString& doctypePublic = s_emptyString,
90 bool xmlDecl = true,
91 const XalanDOMString& standalone = s_emptyString,
92 size_type indent = eDefaultIndentAmount) :
99 xmlDecl,
100 standalone),
101 m_stringBuffer(theManager),
102 m_writer(writer, theManager),
103 m_constants(),
104 m_charPredicate(),
105 m_indentHandler(m_writer , indent)
106 {
107 }
108
111 MemoryManager& theManager,
112 Writer& writer,
114 const XalanDOMString& doctypeSystem = s_emptyString,
115 const XalanDOMString& doctypePublic = s_emptyString,
116 bool xmlDecl = true,
117 const XalanDOMString& standalone = s_emptyString,
118 size_type indent = eDefaultIndentAmount)
119 {
120
121 typedef FormatterToXMLUnicode ThisType;
122
123 XalanAllocationGuard theGuard(theManager, theManager.allocate(sizeof(ThisType)));
124
125 ThisType* const theResult =
126 new (theGuard.get()) ThisType(
128 writer,
129 encoding,
132 xmlDecl,
134 indent);
135
137
138 return theResult;
139 }
140
141 virtual
145
146 Writer*
147 getWriter() const
148 {
149 return m_writer.getWriter();
150 }
151
152 // These are inherited from XalanXMLSerializerBase...
153
154 virtual void
156 {
157 m_indentHandler.setStartNewLine(true);
158
159 m_indentHandler.indent();
160
161 flushBuffer();
162
163 flushWriter();
164 }
165
166 virtual void
168 const XMLCh* const name,
169 AttributeList& attrs)
170 {
171 generateDoctypeDecl(name);
172
173 writeParentTagEnd();
174
175 m_indentHandler.setPreserve(false);
176
177 m_indentHandler.indent();
178
179 m_indentHandler.setStartNewLine(true);
180
181 m_writer.write(value_type(XalanUnicode::charLessThanSign));
182
183 writeName(name);
184
185 const XalanSize_t nAttrs = attrs.getLength();
186
187 for (XalanSize_t i = 0; i < nAttrs ; i++)
188 {
189 processAttribute(attrs.getName(i), attrs.getValue(i));
190 }
191
192 // Flag the current element as not yet having any children.
193 openElementForChildren();
194
195 m_indentHandler.increaseIndent();
196
197 m_indentHandler.setPrevText(false);
198 }
199
200 virtual void
201 endElement(const XMLCh* const name)
202 {
203 m_indentHandler.decreaseIndent();
204
205 const bool hasChildNodes = childNodesWereAdded();
206
207 if (hasChildNodes == true)
208 {
209 m_indentHandler.indent();
210
211 m_writer.write(value_type(XalanUnicode::charLessThanSign));
212 m_writer.write(value_type(XalanUnicode::charSolidus));
213
214 writeName(name);
215 }
216 else
217 {
218 if(m_spaceBeforeClose == true)
219 {
220 m_writer.write(value_type(XalanUnicode::charSpace));
221 }
222
223 m_writer.write(value_type(XalanUnicode::charSolidus));
224 }
225
226 m_writer.write(value_type(XalanUnicode::charGreaterThanSign));
227
228 if (hasChildNodes == true)
229 {
230 m_indentHandler.pop_preserve();
231 }
232
233 m_indentHandler.setPrevText(false);
234 }
235
236 virtual void
238 const XMLCh* const chars,
239 const size_type length)
240 {
241 writeParentTagEnd();
242
243 m_indentHandler.setPreserve(true);
244
245 m_writer.write(chars, length);
246 }
247
248
249 virtual void
251 {
252 writeParentTagEnd();
253
254 m_indentHandler.indent();
255
256 m_writer.write(value_type(XalanUnicode::charAmpersand));
257
258 writeName(name);
259
260 m_writer.write(value_type(XalanUnicode::charSemicolon));
261 }
262
263 virtual void
264 comment(const XMLCh* const data)
265 {
266 writeParentTagEnd();
267
268 m_indentHandler.indent();
269
270 m_writer.write(value_type(XalanUnicode::charLessThanSign));
271 m_writer.write(value_type(XalanUnicode::charExclamationMark));
272 m_writer.write(value_type(XalanUnicode::charHyphenMinus));
273 m_writer.write(value_type(XalanUnicode::charHyphenMinus));
274
275 writeNormalizedData(data, XalanDOMString::length(data));
276
277 m_writer.write(value_type(XalanUnicode::charHyphenMinus));
278 m_writer.write(value_type(XalanUnicode::charHyphenMinus));
279 m_writer.write(value_type(XalanUnicode::charGreaterThanSign));
280
281 m_indentHandler.setStartNewLine(true);
282 }
283
284protected:
285
286 virtual void
288 {
289 m_writer.flushBuffer();
290 }
291
292 virtual void
294 {
295 m_writer.flushWriter();
296 }
297
298 virtual void
300 {
301 // "<?xml version=\""
302 m_writer.write(
303 m_constants.s_xmlHeaderStartString,
304 m_constants.s_xmlHeaderStartStringLength);
305
306 if (m_version.empty() == false)
307 {
308 m_writer.write(m_version);
309 }
310 else
311 {
312 m_writer.write(
313 m_constants.s_defaultVersionString,
314 m_constants.s_defaultVersionStringLength);
315 }
316
317 // "\" encoding=\""
318 m_writer.write(
319 m_constants.s_xmlHeaderEncodingString,
320 m_constants.s_xmlHeaderEncodingStringLength);
321
322 m_writer.write(m_encoding);
323
324 if (m_standalone.empty() == false)
325 {
326 m_writer.write(
327 m_constants.s_xmlHeaderStandaloneString,
328 m_constants.s_xmlHeaderStandaloneStringLength);
329
330 m_writer.write(m_standalone);
331 }
332
333 m_writer.write(
334 m_constants.s_xmlHeaderEndString,
335 m_constants.s_xmlHeaderEndStringLength);
336
337 if (getNeedToOutputDoctypeDecl() == false)
338 {
339 m_indentHandler.outputLineSep();
340 }
341 }
342
343
344 void
346 {
347 // "<!DOCTYPE "
348 m_writer.write(
349 m_constants.s_doctypeHeaderStartString,
350 m_constants.s_doctypeHeaderStartStringLength);
351
352 m_writer.write(name);
353
354 if (m_doctypePublic.empty() == false)
355 {
356 // " PUBLIC \""
357 m_writer.write(
358 m_constants.s_doctypeHeaderPublicString,
359 m_constants.s_doctypeHeaderPublicStringLength);
360
361 writeName(m_doctypePublic.c_str());
362
363 m_writer.write(value_type(XalanUnicode::charQuoteMark));
364 m_writer.write(value_type(XalanUnicode::charSpace));
365 m_writer.write(value_type(XalanUnicode::charQuoteMark));
366 }
367 else
368 {
369 // " SYSTEM \""
370 m_writer.write(
371 m_constants.s_doctypeHeaderSystemString,
372 m_constants.s_doctypeHeaderSystemStringLength);
373 }
374
375 writeName(m_doctypeSystem.c_str());
376
377 m_writer.write(value_type(XalanUnicode::charQuoteMark));
378 m_writer.write(value_type(XalanUnicode::charGreaterThanSign));
379
380 outputNewline();
381 }
382
383
384 void
386 const XMLCh* target,
387 const XMLCh* data)
388 {
389 writeParentTagEnd();
390
391 m_indentHandler.indent();
392
393 m_writer.write(value_type(XalanUnicode::charLessThanSign));
394 m_writer.write(value_type(XalanUnicode::charQuestionMark));
395 writeName(target);
396
397 const size_type len = length(data);
398
399 // We need to make sure there is a least one whitespace character
400 // between the target and the data.
401 if (len > 0 && !isXMLWhitespace(data[0]))
402 {
403 m_writer.write(value_type(XalanUnicode::charSpace));
404 }
405
406 writeNormalizedData(data, len);
407
408 m_writer.write(value_type(XalanUnicode::charQuestionMark));
409 m_writer.write(value_type(XalanUnicode::charGreaterThanSign));
410 }
411
412 void
414 const XMLCh* chars,
415 size_type length)
416 {
417 assert(length != 0);
418
419 writeParentTagEnd();
420
421 m_indentHandler.setPreserve(true);
422
423 size_type i = 0;
425
426 while(i < length)
427 {
428 const XalanDOMChar ch = chars[i];
429
430 if(m_charPredicate.range(ch) == true)
431 {
432 safeWriteContent(chars + firstIndex, i - firstIndex);
433
434 i = writeNormalizedCharBig(chars, i, length);
435
436 ++i;
437
438 firstIndex = i;
439 }
440 else if(m_charPredicate.content(ch) == false)
441 {
442 ++i;
443 }
444 else
445 {
446 safeWriteContent(chars + firstIndex, i - firstIndex);
447
448 writeDefaultEscape(ch);
449
450 ++i;
451
452 firstIndex = i;
453 }
454 }
455
456 safeWriteContent(chars + firstIndex, i - firstIndex);
457
458 m_indentHandler.setPrevText(true);
459 }
460
461
462 void
464 const XMLCh* chars,
465 size_type length)
466 {
467 assert(length != 0);
468
469 writeParentTagEnd();
470
471 m_indentHandler.setPreserve(true);
472
473 m_indentHandler.indent();
474
475 m_writer.write(
476 m_constants.s_cdataOpenString,
477 m_constants.s_cdataOpenStringLength);
478
479 bool outsideCDATA = false;
480
481 writeCDATAChars(chars, length, outsideCDATA);
482
483 if (outsideCDATA == false)
484 {
485 m_writer.write(
486 m_constants.s_cdataCloseString,
487 m_constants.s_cdataCloseStringLength);
488 }
489 }
490
491 /**
492 * Output a line break.
493 */
494 void
496 {
497 m_writer.outputNewline();
498 }
499
500 /**
501 * Escape and write a character.
502 */
503 void
505 {
506 assert(m_charPredicate.content(ch) == true);
507
508 if(!writeDefaultEntity(ch))
509 {
510 if (XalanUnicode::charLF == ch)
511 {
512 outputNewline();
513 }
514 else
515 {
516 if(m_charPredicate.isForbidden(ch) == true)
517 {
518 throwInvalidXMLCharacterException(
519 ch,
520 m_version,
521 getMemoryManager());
522 }
523 else
524 {
525 writeNumericCharacterReference(ch);
526 }
527 }
528 }
529 }
530
531 /**
532 * Escape and write a character in an attribute.
533 */
534 void
536 {
537 assert(m_charPredicate.attribute(ch) == true);
538
539 if(writeDefaultAttributeEntity(ch) == false)
540 {
541 if(m_charPredicate.isForbidden(ch) == true)
542 {
543 throwInvalidXMLCharacterException(
544 ch,
545 m_version,
546 getMemoryManager());
547 }
548 else
549 {
550 writeNumericCharacterReference(ch);
551 }
552
553 }
554 }
555
556 /**
557 * Handle one of the default entities, return false if it
558 * is not a default entity.
559 */
560 bool
562 {
563 if (XalanUnicode::charLessThanSign == ch)
564 {
565 m_writer.write(
566 m_constants.s_lessThanEntityString,
567 m_constants.s_lessThanEntityStringLength);
568 }
569 else if (XalanUnicode::charGreaterThanSign == ch)
570 {
571 m_writer.write(
572 m_constants.s_greaterThanEntityString,
573 m_constants.s_greaterThanEntityStringLength);
574 }
575 else if (XalanUnicode::charAmpersand == ch)
576 {
577 m_writer.write(
578 m_constants.s_ampersandEntityString,
579 m_constants.s_ampersandEntityStringLength);
580 }
581 else
582 {
583 return false;
584 }
585
586 return true;
587 }
588
589 /**
590 * Handle one of the default entities, return false if it
591 * is not a default entity.
592 */
593 bool
595 {
596 if (writeDefaultEntity(ch) == true)
597 {
598 return true;
599 }
600 else if (XalanUnicode::charQuoteMark == ch)
601 {
602 m_writer.write(
603 m_constants.s_quoteEntityString,
604 m_constants.s_quoteEntityStringLength);
605 }
606 else
607 {
608 return false;
609 }
610
611 return true;
612 }
613
614 /**
615 * Check to see if a parent's ">" has been written, and, if
616 * it has not, write it.
617 */
618 void
620 {
621 if(markParentForChildren() == true)
622 {
623 m_writer.write(value_type(XalanUnicode::charGreaterThanSign));
624
625 m_indentHandler.setPrevText(false);
626
627 m_indentHandler.push_preserve();
628 }
629 }
630
631 /**
632 * Write a normalized character to the stream.
633 * @param ch the string to write.
634 * @param start the start offset into the string.
635 * @param length the length of the string.
636 */
640 const XalanDOMChar chars[],
641 size_type start,
642 size_type length)
643 {
644 if (XalanUnicode::charLF == ch)
645 {
646 outputNewline();
647 }
648 else
649 {
650 if(m_charPredicate.isCharRefForbidden(ch))
651 {
652 throwInvalidXMLCharacterException(
653 ch,
654 m_version,
655 getMemoryManager());
656 }
657 else
658 {
659 start = m_writer.write( chars, start, length);
660 }
661 }
662
663 return start;
664 }
665
666 void
668 {
669 m_writer.write(value_type(XalanUnicode::charAmpersand));
670 m_writer.write(value_type(XalanUnicode::charNumberSign));
671
672 m_writer.write(NumberToDOMString(theNumber, m_stringBuffer));
673 m_stringBuffer.clear();
674
675 m_writer.write(value_type(XalanUnicode::charSemicolon));
676 }
677
680 const XalanDOMChar chars[],
681 size_type start,
682 size_type length)
683 {
684 assert(start < length);
685
686 const XalanDOMChar ch = chars[start];
687
688 assert(m_charPredicate.range(ch) == true);
689
690 if (XMLVersion == XML_VERSION_1_1 &&
691 XalanUnicode::charLSEP == ch)
692 {
693 writeNumericCharacterReference(ch);
694 }
695 else
696 {
697 start = m_writer.write(chars, start, length);
698 }
699
700 return start;
701 }
702
703 /**
704 * Write characters for a CDATA section
705 *
706 * @param ch the string to write.
707 * @param length the length of the string.
708 */
709 void
711 const XalanDOMChar chars[],
712 size_type length,
713 bool& outsideCDATA)
714 {
715 size_type i = 0;
716
717 while(i < length)
718 {
719 // If "]]>", which would close the CDATA appears in
720 // the content, we have to put the first two characters
721 // in the CDATA section, close the CDATA section, then
722 // open a new one and add the last character.
723
724 const XalanDOMChar theChar = chars[i];
725
726 if (theChar == XalanUnicode::charRightSquareBracket &&
727 i - length > 2 &&
728 XalanUnicode::charRightSquareBracket == chars[i + 1] &&
729 XalanUnicode::charGreaterThanSign == chars[i + 2])
730 {
731 if (outsideCDATA == true)
732 {
733 m_writer.write(
734 m_constants.s_cdataCloseString,
735 m_constants.s_cdataCloseStringLength);
736 }
737
738 m_writer.write(value_type(XalanUnicode::charRightSquareBracket));
739 m_writer.write(value_type(XalanUnicode::charRightSquareBracket));
740
741 m_writer.write(
742 m_constants.s_cdataCloseString,
743 m_constants.s_cdataCloseStringLength);
744
745 m_writer.write(
746 m_constants.s_cdataOpenString,
747 m_constants.s_cdataOpenStringLength);
748
749 m_writer.write(value_type(XalanUnicode::charGreaterThanSign));
750
751 outsideCDATA = false;
752
753 i += 2;
754 }
755 else
756 {
757 if (XalanUnicode::charLF == theChar)
758 {
759 outputNewline();
760 }
761 else if(m_charPredicate.isCharRefForbidden(theChar))
762 {
763 throwInvalidXMLCharacterException(
764 theChar,
765 m_version,
766 getMemoryManager());
767 }
768 else
769 {
770 i = m_writer.writeCDATAChar(chars, i, length, outsideCDATA);
771 }
772 }
773
774 ++i;
775 }
776
777 if(outsideCDATA == true)
778 {
779 m_writer.write(
780 m_constants.s_cdataOpenString,
781 m_constants.s_cdataOpenStringLength);
782 }
783 }
784
785
786 /**
787 * Write an attribute string.
788 *
789 * @param theString The string to write.
790 * @param theStringLength The length of the string.
791 */
792 void
794 const XalanDOMChar* theString,
796 {
797 assert(theString != 0);
798
799 size_type i = 0;
801
802 while(i < theStringLength)
803 {
804 const XalanDOMChar ch = theString[i];
805
806 if(m_charPredicate.range(ch) == true)
807 {
808 safeWriteContent(theString + firstIndex, i - firstIndex);
809
810 i = writeNormalizedCharBig(theString, i, theStringLength);
811
812 ++i;
813
814 firstIndex = i;
815 }
816 else if (m_charPredicate.attribute(ch) == false)
817 {
818 ++i;
819 }
820 else
821 {
822 safeWriteContent(theString + firstIndex, i - firstIndex);
823
824 writeDefaultAttributeEscape(ch);
825
826 ++i;
827
828 firstIndex = i;
829 }
830 }
831
832 safeWriteContent(theString + firstIndex, i - firstIndex);
833 }
834
835private:
836
837 /**
838 * Process an attribute.
839 * @param name The name of the attribute.
840 * @param value The value of the attribute.
841 */
842 void
843 processAttribute(
844 const XalanDOMChar* name,
845 const XalanDOMChar* value)
846 {
847 m_writer.write(value_type(XalanUnicode::charSpace));
848 writeName(name);
849 m_writer.write(value_type(XalanUnicode::charEqualsSign));
850 m_writer.write(value_type(XalanUnicode::charQuoteMark));
851 writeAttrString(value, length(value));
852 m_writer.write(value_type(XalanUnicode::charQuoteMark));
853 }
854
855 /**
856 * Write normalized data.
857 * @param theData the data to write.
858 * @param theLength the data to write.
859 */
860 void
861 writeNormalizedData(
862 const XalanDOMChar* theData,
863 size_type theLength)
864 {
865 for (size_type i = 0; i < theLength; ++i)
866 {
867 const XalanDOMChar theChar = theData[i];
868
869 i = writeNormalizedChar(theChar, theData, i, theLength);
870 }
871 }
872
873 void
874 safeWriteContent(
875 const XalanDOMChar* theChars,
876 size_type theLength)
877 {
878 for(size_type i = 0; i < theLength; ++i)
879 {
880 m_writer.write(value_type(theChars[i]));
881 }
882 }
883
884 void
885 writeName(const XalanDOMChar* theChars)
886 {
887 assert( theChars != 0);
888
889 m_writer.writeNameChar(theChars, length(theChars));
890 }
891
892private:
893
894 // These are not implemented.
895 FormatterToXMLUnicode(const FormatterToXMLUnicode&);
896
897 FormatterToXMLUnicode&
898 operator=(const FormatterToXMLUnicode&);
899
900 bool
901 operator==(const FormatterToXMLUnicode&) const;
902
903
904 // Data members...
905 XalanDOMString m_stringBuffer;
906
907 UnicodeWriter m_writer;
908
909 ConstantsType m_constants;
910
911 CharPredicate m_charPredicate;
912
913 IndentHandler m_indentHandler;
914};
915
916
917
918}
919
920
921
922#endif // FORMATTERTOXML_UNICODE_HEADER_GUARD_1357924680
#define XALAN_XMLSUPPORT_EXPORT
#define XALAN_CPP_NAMESPACE
Xalan-C++ namespace, including major and minor version.
FormatterToXMLUnicode formats SAX-style events into XML.
void writeDefaultEscape(XalanDOMChar ch)
Escape and write a character.
void writeProcessingInstruction(const XMLCh *target, const XMLCh *data)
void writeDefaultAttributeEscape(XalanDOMChar ch)
Escape and write a character in an attribute.
UnicodeWriter::value_type value_type
virtual void charactersRaw(const XMLCh *const chars, const size_type length)
void writeNumericCharacterReference(XMLUInt32 theNumber)
void writeCDATAChars(const XalanDOMChar chars[], size_type length, bool &outsideCDATA)
Write characters for a CDATA section.
void writeCharacters(const XMLCh *chars, size_type length)
void writeAttrString(const XalanDOMChar *theString, size_type theStringLength)
Write an attribute string.
FormatterToXMLUnicode(MemoryManager &theManager, Writer &writer, const XalanDOMString &encoding, const XalanDOMString &doctypeSystem=s_emptyString, const XalanDOMString &doctypePublic=s_emptyString, bool xmlDecl=true, const XalanDOMString &standalone=s_emptyString, size_type indent=eDefaultIndentAmount)
Constructor.
size_type writeNormalizedChar(XalanDOMChar ch, const XalanDOMChar chars[], size_type start, size_type length)
Write a normalized character to the stream.
virtual void startElement(const XMLCh *const name, AttributeList &attrs)
bool writeDefaultAttributeEntity(XalanDOMChar ch)
Handle one of the default entities, return false if it is not a default entity.
virtual void entityReference(const XMLCh *const name)
Receive notification of a entityReference.
size_type writeNormalizedCharBig(const XalanDOMChar chars[], size_type start, size_type length)
void writeCDATA(const XMLCh *chars, size_type length)
void writeDoctypeDecl(const XalanDOMChar *name)
bool writeDefaultEntity(XalanDOMChar ch)
Handle one of the default entities, return false if it is not a default entity.
virtual void comment(const XMLCh *const data)
Called when a Comment is to be constructed.
void outputNewline()
Output a line break.
virtual void endElement(const XMLCh *const name)
static FormatterToXMLUnicode * create(MemoryManager &theManager, Writer &writer, const XalanDOMString &encoding, const XalanDOMString &doctypeSystem=s_emptyString, const XalanDOMString &doctypePublic=s_emptyString, bool xmlDecl=true, const XalanDOMString &standalone=s_emptyString, size_type indent=eDefaultIndentAmount)
void writeParentTagEnd()
Check to see if a parent's ">" has been written, and, if it has not, write it.
XalanXMLSerializerBase serves as a base class for XML serializers based on FormatterListener events.
XalanDOMString::size_type length(const XalanDOMString &theString)
Get the length of a XalanDOMString.
bool isXMLWhitespace(XalanDOMChar theChar)
Determines whether character represents white space.
size_t size_type
Definition XalanMap.hpp:46
bool operator==(const XalanVector< Type > &theLHS, const XalanVector< Type > &theRHS)
NumberToDOMString(double theValue, XalanDOMString &theResult)
Converts a double value into a XalanDOMString.