1:
37:
38: package ;
39:
40: import ;
41:
42: import ;
43: import ;
44:
45: import ;
46: import ;
47:
48: import ;
49:
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56:
57: import ;
58: import ;
59: import ;
60:
61:
67:
68: public class HTMLWriter
69: extends AbstractWriter
70: {
71:
74: private Writer outWriter = null;
75:
76:
79: private HTMLDocument htmlDoc = null;
80:
81:
84: private HashSet openEmbededTagHashSet = null;
85:
86: private String new_line_str = "" + NEWLINE;
87:
88: private char[] html_entity_char_arr = {'<', '>', '&', '"'};
89:
90: private String[] html_entity_escape_str_arr = {"<", ">", "&",
91: """};
92:
93:
94: private int doc_pos = -1;
95: private int doc_len = -1;
96: private int doc_offset_remaining = -1;
97: private int doc_len_remaining = -1;
98: private HashSet htmlFragmentParentHashSet = null;
99: private Element startElem = null;
100: private Element endElem = null;
101: private boolean fg_pass_start_elem = false;
102: private boolean fg_pass_end_elem = false;
103:
104:
110: public HTMLWriter(Writer writer, HTMLDocument doc)
111: {
112: super(writer, doc);
113: outWriter = writer;
114: htmlDoc = doc;
115: openEmbededTagHashSet = new HashSet();
116: }
117:
118:
127: public HTMLWriter(Writer writer, HTMLDocument doc, int pos, int len)
128: {
129: super(writer, doc, pos, len);
130: outWriter = writer;
131: htmlDoc = doc;
132: openEmbededTagHashSet = new HashSet();
133:
134: doc_pos = pos;
135: doc_offset_remaining = pos;
136: doc_len = len;
137: doc_len_remaining = len;
138: htmlFragmentParentHashSet = new HashSet();
139: }
140:
141:
148: public void write()
149: throws IOException, BadLocationException
150: {
151: Element rootElem = htmlDoc.getDefaultRootElement();
152:
153: if (doc_pos == -1 && doc_len == -1)
154: {
155:
156: traverse(rootElem);
157: }
158: else
159: {
160:
161: if (doc_pos == -1 || doc_len == -1)
162: throw new BadLocationException("Bad Location("
163: + doc_pos + ", " + doc_len + ")", doc_pos);
164:
165: startElem = htmlDoc.getCharacterElement(doc_pos);
166:
167: int start_offset = startElem.getStartOffset();
168:
169:
170:
171: if (start_offset > 0)
172: doc_offset_remaining = doc_offset_remaining - start_offset;
173:
174: Element tempParentElem = startElem;
175:
176: while ((tempParentElem = tempParentElem.getParentElement()) != null)
177: {
178: if (!htmlFragmentParentHashSet.contains(tempParentElem))
179: htmlFragmentParentHashSet.add(tempParentElem);
180: }
181:
182:
183:
184: endElem = htmlDoc.getCharacterElement(doc_pos + doc_len - 1);
185:
186: tempParentElem = endElem;
187:
188: while ((tempParentElem = tempParentElem.getParentElement()) != null)
189: {
190: if (!htmlFragmentParentHashSet.contains(tempParentElem))
191: htmlFragmentParentHashSet.add(tempParentElem);
192: }
193:
194:
195: traverseHtmlFragment(rootElem);
196:
197: }
198:
199:
200: Object[] tag_arr = openEmbededTagHashSet.toArray();
201:
202: for (int i = 0; i < tag_arr.length; i++)
203: {
204: writeRaw("</" + tag_arr[i].toString() + ">");
205: }
206:
207: }
208:
209:
219: protected void writeAttributes(AttributeSet attrSet)
220: throws IOException
221: {
222: Enumeration attrNameEnum = attrSet.getAttributeNames();
223:
224: while (attrNameEnum.hasMoreElements())
225: {
226: Object key = attrNameEnum.nextElement();
227: Object value = attrSet.getAttribute(key);
228:
229:
230: if (!((key instanceof HTML.Tag) || (key instanceof StyleConstants)
231: || (key == HTML.Attribute.ENDTAG)))
232: {
233: if (key == HTML.Attribute.SELECTED)
234: writeRaw(" selected");
235: else if (key == HTML.Attribute.CHECKED)
236: writeRaw(" checked");
237: else
238: writeRaw(" " + key + "=\"" + value + "\"");
239: }
240:
241: }
242:
243: }
244:
245:
254: protected void emptyTag(Element paramElem)
255: throws IOException, BadLocationException
256: {
257: String elem_name = paramElem.getName();
258: AttributeSet attrSet = paramElem.getAttributes();
259:
260: writeRaw("<" + elem_name);
261: writeAttributes(attrSet);
262: writeRaw(">");
263:
264: if (isBlockTag(attrSet))
265: {
266: writeRaw("</" + elem_name + ">");
267: }
268:
269: }
270:
271:
272:
280: protected boolean isBlockTag(AttributeSet attrSet)
281: {
282: return ((HTML.Tag)
283: attrSet.getAttribute(StyleConstants.NameAttribute)).isBlock();
284: }
285:
286:
294: protected void startTag(Element paramElem)
295: throws IOException, BadLocationException
296: {
297:
298: String elem_name = paramElem.getName();
299: AttributeSet attrSet = paramElem.getAttributes();
300:
301: indent();
302: writeRaw("<" + elem_name);
303: writeAttributes(attrSet);
304: writeRaw(">");
305: writeLineSeparator();
306: incrIndent();
307:
308: }
309:
310:
311:
319: protected void textAreaContent(AttributeSet attrSet)
320: throws IOException, BadLocationException
321: {
322: writeLineSeparator();
323: indent();
324: writeRaw("<textarea");
325: writeAttributes(attrSet);
326: writeRaw(">");
327:
328: Document tempDocument =
329: (Document) attrSet.getAttribute(StyleConstants.ModelAttribute);
330:
331: writeRaw(tempDocument.getText(0, tempDocument.getLength()));
332: indent();
333: writeRaw("</textarea>");
334:
335: }
336:
337:
338:
346: protected void text(Element paramElem)
347: throws IOException, BadLocationException
348: {
349: int offset = paramElem.getStartOffset();
350: int len = paramElem.getEndOffset() - paramElem.getStartOffset();
351: String txt_value = htmlDoc.getText(offset, len);
352:
353: writeContent(txt_value);
354:
355: }
356:
357:
358:
365: protected void selectContent(AttributeSet attrSet)
366: throws IOException
367: {
368: writeLineSeparator();
369: indent();
370: writeRaw("<select");
371: writeAttributes(attrSet);
372: writeRaw(">");
373: incrIndent();
374: writeLineSeparator();
375:
376: ComboBoxModel comboBoxModel =
377: (ComboBoxModel) attrSet.getAttribute(StyleConstants.ModelAttribute);
378:
379: for (int i = 0; i < comboBoxModel.getSize(); i++)
380: {
381: writeOption((Option) comboBoxModel.getElementAt(i));
382: }
383:
384: decrIndent();
385: indent();
386: writeRaw("</select>");
387:
388: }
389:
390:
397: protected void writeOption(Option option)
398: throws IOException
399: {
400: indent();
401: writeRaw("<option");
402: writeAttributes(option.getAttributes());
403: writeRaw(">");
404:
405: writeContent(option.getLabel());
406:
407: writeRaw("</option>");
408: writeLineSeparator();
409:
410: }
411:
412:
419: protected void endTag(Element paramElem)
420: throws IOException
421: {
422: String elem_name = paramElem.getName();
423:
424:
425: decrIndent();
426: indent();
427: writeRaw("</" + elem_name + ">");
428: writeLineSeparator();
429:
430: }
431:
432:
437: protected void comment(Element paramElem)
438: throws IOException, BadLocationException
439: {
440: AttributeSet attrSet = paramElem.getAttributes();
441:
442: String comment_str = (String) attrSet.getAttribute(HTML.Attribute.COMMENT);
443:
444: writeRaw("<!--" + comment_str + "-->");
445:
446: }
447:
448:
449:
458: protected boolean synthesizedElement(Element element)
459: {
460: AttributeSet attrSet = element.getAttributes();
461: Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute);
462:
463: if (tagType == HTML.Tag.CONTENT || tagType == HTML.Tag.COMMENT
464: || tagType == HTML.Tag.IMPLIED)
465: return true;
466: else
467: return false;
468: }
469:
470:
482: protected boolean matchNameAttribute(AttributeSet attrSet, HTML.Tag tag)
483: {
484: Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute);
485:
486: if (tagType == tag)
487: return true;
488: else
489: return false;
490: }
491:
492:
493:
502: protected void writeEmbeddedTags(AttributeSet attrSet)
503: throws IOException
504: {
505: Enumeration attrNameEnum = attrSet.getAttributeNames();
506:
507: while (attrNameEnum.hasMoreElements())
508: {
509: Object key = attrNameEnum.nextElement();
510: Object value = attrSet.getAttribute(key);
511:
512: if (key instanceof HTML.Tag)
513: {
514: if (!openEmbededTagHashSet.contains(key))
515: {
516: writeRaw("<" + key);
517: writeAttributes((AttributeSet) value);
518: writeRaw(">");
519: openEmbededTagHashSet.add(key);
520: }
521: }
522: }
523:
524: }
525:
526:
527:
535: protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet)
536: throws IOException
537: {
538: Object[] tag_arr = openEmbededTagHashSet.toArray();
539:
540: for (int i = 0; i < tag_arr.length; i++)
541: {
542: HTML.Tag key = (HTML.Tag) tag_arr[i];
543:
544: if (!attrSet.isDefined(key))
545: {
546: writeRaw("</" + key.toString() + ">");
547: openEmbededTagHashSet.remove(key);
548: }
549: }
550:
551: }
552:
553:
554:
560: protected void writeLineSeparator()
561: throws IOException
562: {
563: writeRaw(new_line_str);
564: }
565:
566:
576: protected void output(char[] chars, int off, int len)
577: throws IOException
578: {
579: CPStringBuilder strBuffer = new CPStringBuilder();
580:
581: for (int i = 0; i < chars.length; i++)
582: {
583: if (isCharHtmlEntity(chars[i]))
584: strBuffer.append(escapeCharHtmlEntity(chars[i]));
585: else
586: strBuffer.append(chars[i]);
587: }
588:
589: writeRaw(strBuffer.toString());
590:
591: }
592:
593:
594:
595:
596:
597:
604: private void traverse(Element paramElem)
605: throws IOException, BadLocationException
606: {
607: Element currElem = paramElem;
608:
609: AttributeSet attrSet = currElem.getAttributes();
610:
611: closeOutUnwantedEmbeddedTags(attrSet);
612:
613:
614: if (synthesizedElement(paramElem))
615: {
616: if (matchNameAttribute(attrSet, HTML.Tag.CONTENT))
617: {
618: writeEmbeddedTags(attrSet);
619: text(currElem);
620: }
621: else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT))
622: {
623: comment(currElem);
624: }
625: else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
626: {
627: int child_elem_count = currElem.getElementCount();
628:
629: if (child_elem_count > 0)
630: {
631: for (int i = 0; i < child_elem_count; i++)
632: {
633: Element childElem = paramElem.getElement(i);
634:
635: traverse(childElem);
636:
637: }
638: }
639: }
640: }
641: else
642: {
643:
644:
645: if (matchNameAttribute(attrSet, HTML.Tag.TITLE))
646: {
647: boolean fg_is_end_tag = false;
648: Enumeration attrNameEnum = attrSet.getAttributeNames();
649:
650: while (attrNameEnum.hasMoreElements())
651: {
652: Object key = attrNameEnum.nextElement();
653: Object value = attrSet.getAttribute(key);
654:
655: if (key == HTML.Attribute.ENDTAG && value.equals("true"))
656: fg_is_end_tag = true;
657: }
658:
659: if (fg_is_end_tag)
660: writeRaw("</title>");
661: else
662: {
663: indent();
664: writeRaw("<title>");
665:
666: String title_str =
667: (String) htmlDoc.getProperty(HTMLDocument.TitleProperty);
668:
669: if (title_str != null)
670: writeContent(title_str);
671:
672: }
673: }
674: else if (matchNameAttribute(attrSet, HTML.Tag.PRE))
675: {
676:
677: attrSet = paramElem.getAttributes();
678:
679: indent();
680: writeRaw("<pre");
681: writeAttributes(attrSet);
682: writeRaw(">");
683:
684: int child_elem_count = currElem.getElementCount();
685:
686: for (int i = 0; i < child_elem_count; i++)
687: {
688: Element childElem = paramElem.getElement(i);
689:
690: traverse(childElem);
691:
692: }
693:
694: writeRaw("</pre>");
695:
696: }
697: else if (matchNameAttribute(attrSet, HTML.Tag.SELECT))
698: {
699: selectContent(attrSet);
700: }
701: else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
702: {
703: textAreaContent(attrSet);
704: }
705: else
706: {
707: int child_elem_count = currElem.getElementCount();
708:
709: if (child_elem_count > 0)
710: {
711: startTag(currElem);
712:
713: for (int i = 0; i < child_elem_count; i++)
714: {
715: Element childElem = paramElem.getElement(i);
716:
717: traverse(childElem);
718:
719: }
720:
721: endTag(currElem);
722:
723: }
724: else
725: {
726: emptyTag(currElem);
727: }
728: }
729: }
730:
731: }
732:
733:
734:
741: private void traverseHtmlFragment(Element paramElem)
742: throws IOException, BadLocationException
743: {
744:
745: Element currElem = paramElem;
746:
747: boolean fg_is_fragment_parent_elem = false;
748: boolean fg_is_start_and_end_elem = false;
749:
750: if (htmlFragmentParentHashSet.contains(paramElem))
751: fg_is_fragment_parent_elem = true;
752:
753: if (paramElem == startElem)
754: fg_pass_start_elem = true;
755:
756: if (paramElem == startElem && paramElem == endElem)
757: fg_is_start_and_end_elem = true;
758:
759: AttributeSet attrSet = currElem.getAttributes();
760:
761: closeOutUnwantedEmbeddedTags(attrSet);
762:
763: if (fg_is_fragment_parent_elem || (fg_pass_start_elem
764: && fg_pass_end_elem == false) || fg_is_start_and_end_elem)
765: {
766:
767: if (synthesizedElement(paramElem))
768: {
769: if (matchNameAttribute(attrSet, HTML.Tag.CONTENT))
770: {
771: writeEmbeddedTags(attrSet);
772:
773: int content_offset = paramElem.getStartOffset();
774: int content_length = currElem.getEndOffset() - content_offset;
775:
776: if (doc_offset_remaining > 0)
777: {
778: if (content_length > doc_offset_remaining)
779: {
780: int split_len = content_length;
781:
782: split_len = split_len - doc_offset_remaining;
783:
784: if (split_len > doc_len_remaining)
785: split_len = doc_len_remaining;
786:
787:
788: String txt_value = htmlDoc.getText(content_offset
789: + doc_offset_remaining, split_len);
790:
791: writeContent(txt_value);
792:
793: doc_offset_remaining = 0;
794: doc_len_remaining = doc_len_remaining - split_len;
795: }
796: else
797: {
798:
799:
800: doc_offset_remaining = doc_offset_remaining
801: - content_length;
802: }
803: }
804: else if (content_length <= doc_len_remaining)
805: {
806:
807: text(currElem);
808: doc_len_remaining = doc_len_remaining - content_length;
809: }
810: else
811: {
812:
813: String txt_value = htmlDoc.getText(content_offset,
814: doc_len_remaining);
815:
816: writeContent(txt_value);
817:
818: doc_len_remaining = 0;
819: }
820:
821: }
822: else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT))
823: {
824: comment(currElem);
825: }
826: else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
827: {
828: int child_elem_count = currElem.getElementCount();
829:
830: if (child_elem_count > 0)
831: {
832: for (int i = 0; i < child_elem_count; i++)
833: {
834: Element childElem = paramElem.getElement(i);
835:
836: traverseHtmlFragment(childElem);
837:
838: }
839: }
840: }
841: }
842: else
843: {
844:
845:
846: if (paramElem.isLeaf())
847: {
848: if (doc_offset_remaining > 0)
849: {
850: doc_offset_remaining--;
851: }
852: else if (doc_len_remaining > 0)
853: {
854: doc_len_remaining--;
855: }
856: }
857:
858:
859:
860: if (matchNameAttribute(attrSet, HTML.Tag.TITLE))
861: {
862: boolean fg_is_end_tag = false;
863: Enumeration attrNameEnum = attrSet.getAttributeNames();
864:
865: while (attrNameEnum.hasMoreElements())
866: {
867: Object key = attrNameEnum.nextElement();
868: Object value = attrSet.getAttribute(key);
869:
870: if (key == HTML.Attribute.ENDTAG && value.equals("true"))
871: fg_is_end_tag = true;
872: }
873:
874: if (fg_is_end_tag)
875: writeRaw("</title>");
876: else
877: {
878: indent();
879: writeRaw("<title>");
880:
881: String title_str =
882: (String) htmlDoc.getProperty(HTMLDocument.TitleProperty);
883:
884: if (title_str != null)
885: writeContent(title_str);
886:
887: }
888: }
889: else if (matchNameAttribute(attrSet, HTML.Tag.PRE))
890: {
891:
892: attrSet = paramElem.getAttributes();
893:
894: indent();
895: writeRaw("<pre");
896: writeAttributes(attrSet);
897: writeRaw(">");
898:
899: int child_elem_count = currElem.getElementCount();
900:
901: for (int i = 0; i < child_elem_count; i++)
902: {
903: Element childElem = paramElem.getElement(i);
904:
905: traverseHtmlFragment(childElem);
906:
907: }
908:
909: writeRaw("</pre>");
910:
911: }
912: else if (matchNameAttribute(attrSet, HTML.Tag.SELECT))
913: {
914: selectContent(attrSet);
915: }
916: else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
917: {
918: textAreaContent(attrSet);
919: }
920: else
921: {
922: int child_elem_count = currElem.getElementCount();
923:
924: if (child_elem_count > 0)
925: {
926: startTag(currElem);
927:
928: for (int i = 0; i < child_elem_count; i++)
929: {
930: Element childElem = paramElem.getElement(i);
931:
932: traverseHtmlFragment(childElem);
933:
934: }
935:
936: endTag(currElem);
937:
938: }
939: else
940: {
941: emptyTag(currElem);
942: }
943: }
944: }
945:
946: }
947:
948:
949: if (paramElem == endElem)
950: fg_pass_end_elem = true;
951:
952: }
953:
954:
955:
962: private void writeRaw(String param_str)
963: throws IOException
964: {
965: super.output(param_str.toCharArray(), 0, param_str.length());
966: }
967:
968:
969:
976: private void writeContent(String param_str)
977: throws IOException
978: {
979: char[] str_char_arr = param_str.toCharArray();
980:
981: if (hasHtmlEntity(param_str))
982: output(str_char_arr, 0, str_char_arr.length);
983: else
984: super.output(str_char_arr, 0, str_char_arr.length);
985:
986: }
987:
988:
996: private void writeAllAttributes(AttributeSet attrSet)
997: throws IOException
998: {
999: Enumeration attrNameEnum = attrSet.getAttributeNames();
1000:
1001: while (attrNameEnum.hasMoreElements())
1002: {
1003: Object key = attrNameEnum.nextElement();
1004: Object value = attrSet.getAttribute(key);
1005:
1006: writeRaw(" " + key + "=\"" + value + "\"");
1007: writeRaw(" " + key.getClass().toString() + "=\""
1008: + value.getClass().toString() + "\"");
1009: }
1010:
1011: }
1012:
1013:
1014:
1022: private boolean hasHtmlEntity(String param_str)
1023: {
1024: boolean ret_bool = false;
1025:
1026: for (int i = 0; i < html_entity_char_arr.length; i++)
1027: {
1028: if (param_str.indexOf(html_entity_char_arr[i]) != -1)
1029: {
1030: ret_bool = true;
1031: break;
1032: }
1033: }
1034:
1035: return ret_bool;
1036: }
1037:
1038:
1046: private boolean isCharHtmlEntity(char param_char)
1047: {
1048: boolean ret_bool = false;
1049:
1050: for (int i = 0; i < html_entity_char_arr.length; i++)
1051: {
1052: if (param_char == html_entity_char_arr[i])
1053: {
1054: ret_bool = true;
1055: break;
1056: }
1057: }
1058:
1059: return ret_bool;
1060: }
1061:
1062:
1070: private String escapeCharHtmlEntity(char param_char)
1071: {
1072: String ret_str = "" + param_char;
1073:
1074: for (int i = 0; i < html_entity_char_arr.length; i++)
1075: {
1076: if (param_char == html_entity_char_arr[i])
1077: {
1078: ret_str = html_entity_escape_str_arr[i];
1079: break;
1080: }
1081: }
1082:
1083: return ret_str;
1084: }
1085:
1086: }