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<HTML.Tag> openEmbeddedTagHashSet = 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<Element> 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: openEmbeddedTagHashSet = new HashSet<HTML.Tag>();
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: openEmbeddedTagHashSet = new HashSet<HTML.Tag>();
133:
134: doc_pos = pos;
135: doc_offset_remaining = pos;
136: doc_len = len;
137: doc_len_remaining = len;
138: htmlFragmentParentHashSet = new HashSet<Element>();
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: HTML.Tag[] tag_arr =
201: openEmbeddedTagHashSet.toArray(new HTML.Tag[openEmbeddedTagHashSet.size()]);
202:
203: for (int i = 0; i < tag_arr.length; i++)
204: {
205: writeRaw("</" + tag_arr[i].toString() + ">");
206: }
207:
208: }
209:
210:
220: protected void writeAttributes(AttributeSet attrSet)
221: throws IOException
222: {
223: Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
224:
225: while (attrNameEnum.hasMoreElements())
226: {
227: Object key = attrNameEnum.nextElement();
228: Object value = attrSet.getAttribute(key);
229:
230:
231: if (!((key instanceof HTML.Tag) || (key instanceof StyleConstants)
232: || (key == HTML.Attribute.ENDTAG)))
233: {
234: if (key == HTML.Attribute.SELECTED)
235: writeRaw(" selected");
236: else if (key == HTML.Attribute.CHECKED)
237: writeRaw(" checked");
238: else
239: writeRaw(" " + key + "=\"" + value + "\"");
240: }
241:
242: }
243:
244: }
245:
246:
255: protected void emptyTag(Element paramElem)
256: throws IOException, BadLocationException
257: {
258: String elem_name = paramElem.getName();
259: AttributeSet attrSet = paramElem.getAttributes();
260:
261: writeRaw("<" + elem_name);
262: writeAttributes(attrSet);
263: writeRaw(">");
264:
265: if (isBlockTag(attrSet))
266: {
267: writeRaw("</" + elem_name + ">");
268: }
269:
270: }
271:
272:
273:
281: protected boolean isBlockTag(AttributeSet attrSet)
282: {
283: return ((HTML.Tag)
284: attrSet.getAttribute(StyleConstants.NameAttribute)).isBlock();
285: }
286:
287:
295: protected void startTag(Element paramElem)
296: throws IOException, BadLocationException
297: {
298:
299: String elem_name = paramElem.getName();
300: AttributeSet attrSet = paramElem.getAttributes();
301:
302: indent();
303: writeRaw("<" + elem_name);
304: writeAttributes(attrSet);
305: writeRaw(">");
306: writeLineSeparator();
307: incrIndent();
308:
309: }
310:
311:
312:
320: protected void textAreaContent(AttributeSet attrSet)
321: throws IOException, BadLocationException
322: {
323: writeLineSeparator();
324: indent();
325: writeRaw("<textarea");
326: writeAttributes(attrSet);
327: writeRaw(">");
328:
329: Document tempDocument =
330: (Document) attrSet.getAttribute(StyleConstants.ModelAttribute);
331:
332: writeRaw(tempDocument.getText(0, tempDocument.getLength()));
333: indent();
334: writeRaw("</textarea>");
335:
336: }
337:
338:
339:
347: protected void text(Element paramElem)
348: throws IOException, BadLocationException
349: {
350: int offset = paramElem.getStartOffset();
351: int len = paramElem.getEndOffset() - paramElem.getStartOffset();
352: String txt_value = htmlDoc.getText(offset, len);
353:
354: writeContent(txt_value);
355:
356: }
357:
358:
359:
366: protected void selectContent(AttributeSet attrSet)
367: throws IOException
368: {
369: writeLineSeparator();
370: indent();
371: writeRaw("<select");
372: writeAttributes(attrSet);
373: writeRaw(">");
374: incrIndent();
375: writeLineSeparator();
376:
377: ComboBoxModel comboBoxModel =
378: (ComboBoxModel) attrSet.getAttribute(StyleConstants.ModelAttribute);
379:
380: for (int i = 0; i < comboBoxModel.getSize(); i++)
381: {
382: writeOption((Option) comboBoxModel.getElementAt(i));
383: }
384:
385: decrIndent();
386: indent();
387: writeRaw("</select>");
388:
389: }
390:
391:
398: protected void writeOption(Option option)
399: throws IOException
400: {
401: indent();
402: writeRaw("<option");
403: writeAttributes(option.getAttributes());
404: writeRaw(">");
405:
406: writeContent(option.getLabel());
407:
408: writeRaw("</option>");
409: writeLineSeparator();
410:
411: }
412:
413:
420: protected void endTag(Element paramElem)
421: throws IOException
422: {
423: String elem_name = paramElem.getName();
424:
425:
426: decrIndent();
427: indent();
428: writeRaw("</" + elem_name + ">");
429: writeLineSeparator();
430:
431: }
432:
433:
438: protected void comment(Element paramElem)
439: throws IOException, BadLocationException
440: {
441: AttributeSet attrSet = paramElem.getAttributes();
442:
443: String comment_str = (String) attrSet.getAttribute(HTML.Attribute.COMMENT);
444:
445: writeRaw("<!--" + comment_str + "-->");
446:
447: }
448:
449:
450:
459: protected boolean synthesizedElement(Element element)
460: {
461: AttributeSet attrSet = element.getAttributes();
462: Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute);
463:
464: if (tagType == HTML.Tag.CONTENT || tagType == HTML.Tag.COMMENT
465: || tagType == HTML.Tag.IMPLIED)
466: return true;
467: else
468: return false;
469: }
470:
471:
483: protected boolean matchNameAttribute(AttributeSet attrSet, HTML.Tag tag)
484: {
485: Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute);
486:
487: if (tagType == tag)
488: return true;
489: else
490: return false;
491: }
492:
493:
494:
503: protected void writeEmbeddedTags(AttributeSet attrSet)
504: throws IOException
505: {
506: Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
507:
508: while (attrNameEnum.hasMoreElements())
509: {
510: Object key = attrNameEnum.nextElement();
511: Object value = attrSet.getAttribute(key);
512:
513: if (key instanceof HTML.Tag)
514: {
515: if (!openEmbeddedTagHashSet.contains(key))
516: {
517: writeRaw("<" + key);
518: writeAttributes((AttributeSet) value);
519: writeRaw(">");
520: openEmbeddedTagHashSet.add((HTML.Tag) key);
521: }
522: }
523: }
524:
525: }
526:
527:
528:
536: protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet)
537: throws IOException
538: {
539: HTML.Tag[] tag_arr =
540: openEmbeddedTagHashSet.toArray(new HTML.Tag[openEmbeddedTagHashSet.size()]);
541:
542: for (int i = 0; i < tag_arr.length; i++)
543: {
544: HTML.Tag key = tag_arr[i];
545:
546: if (!attrSet.isDefined(key))
547: {
548: writeRaw("</" + key.toString() + ">");
549: openEmbeddedTagHashSet.remove(key);
550: }
551: }
552:
553: }
554:
555:
556:
562: protected void writeLineSeparator()
563: throws IOException
564: {
565: writeRaw(new_line_str);
566: }
567:
568:
578: protected void output(char[] chars, int off, int len)
579: throws IOException
580: {
581: CPStringBuilder strBuffer = new CPStringBuilder();
582:
583: for (int i = 0; i < chars.length; i++)
584: {
585: if (isCharHtmlEntity(chars[i]))
586: strBuffer.append(escapeCharHtmlEntity(chars[i]));
587: else
588: strBuffer.append(chars[i]);
589: }
590:
591: writeRaw(strBuffer.toString());
592:
593: }
594:
595:
596:
597:
598:
599:
606: private void traverse(Element paramElem)
607: throws IOException, BadLocationException
608: {
609: Element currElem = paramElem;
610:
611: AttributeSet attrSet = currElem.getAttributes();
612:
613: closeOutUnwantedEmbeddedTags(attrSet);
614:
615:
616: if (synthesizedElement(paramElem))
617: {
618: if (matchNameAttribute(attrSet, HTML.Tag.CONTENT))
619: {
620: writeEmbeddedTags(attrSet);
621: text(currElem);
622: }
623: else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT))
624: {
625: comment(currElem);
626: }
627: else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
628: {
629: int child_elem_count = currElem.getElementCount();
630:
631: if (child_elem_count > 0)
632: {
633: for (int i = 0; i < child_elem_count; i++)
634: {
635: Element childElem = paramElem.getElement(i);
636:
637: traverse(childElem);
638:
639: }
640: }
641: }
642: }
643: else
644: {
645:
646:
647: if (matchNameAttribute(attrSet, HTML.Tag.TITLE))
648: {
649: boolean fg_is_end_tag = false;
650: Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
651:
652: while (attrNameEnum.hasMoreElements())
653: {
654: Object key = attrNameEnum.nextElement();
655: Object value = attrSet.getAttribute(key);
656:
657: if (key == HTML.Attribute.ENDTAG && value.equals("true"))
658: fg_is_end_tag = true;
659: }
660:
661: if (fg_is_end_tag)
662: writeRaw("</title>");
663: else
664: {
665: indent();
666: writeRaw("<title>");
667:
668: String title_str =
669: (String) htmlDoc.getProperty(HTMLDocument.TitleProperty);
670:
671: if (title_str != null)
672: writeContent(title_str);
673:
674: }
675: }
676: else if (matchNameAttribute(attrSet, HTML.Tag.PRE))
677: {
678:
679: attrSet = paramElem.getAttributes();
680:
681: indent();
682: writeRaw("<pre");
683: writeAttributes(attrSet);
684: writeRaw(">");
685:
686: int child_elem_count = currElem.getElementCount();
687:
688: for (int i = 0; i < child_elem_count; i++)
689: {
690: Element childElem = paramElem.getElement(i);
691:
692: traverse(childElem);
693:
694: }
695:
696: writeRaw("</pre>");
697:
698: }
699: else if (matchNameAttribute(attrSet, HTML.Tag.SELECT))
700: {
701: selectContent(attrSet);
702: }
703: else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
704: {
705: textAreaContent(attrSet);
706: }
707: else
708: {
709: int child_elem_count = currElem.getElementCount();
710:
711: if (child_elem_count > 0)
712: {
713: startTag(currElem);
714:
715: for (int i = 0; i < child_elem_count; i++)
716: {
717: Element childElem = paramElem.getElement(i);
718:
719: traverse(childElem);
720:
721: }
722:
723: endTag(currElem);
724:
725: }
726: else
727: {
728: emptyTag(currElem);
729: }
730: }
731: }
732:
733: }
734:
735:
736:
743: private void traverseHtmlFragment(Element paramElem)
744: throws IOException, BadLocationException
745: {
746:
747: Element currElem = paramElem;
748:
749: boolean fg_is_fragment_parent_elem = false;
750: boolean fg_is_start_and_end_elem = false;
751:
752: if (htmlFragmentParentHashSet.contains(paramElem))
753: fg_is_fragment_parent_elem = true;
754:
755: if (paramElem == startElem)
756: fg_pass_start_elem = true;
757:
758: if (paramElem == startElem && paramElem == endElem)
759: fg_is_start_and_end_elem = true;
760:
761: AttributeSet attrSet = currElem.getAttributes();
762:
763: closeOutUnwantedEmbeddedTags(attrSet);
764:
765: if (fg_is_fragment_parent_elem || (fg_pass_start_elem
766: && fg_pass_end_elem == false) || fg_is_start_and_end_elem)
767: {
768:
769: if (synthesizedElement(paramElem))
770: {
771: if (matchNameAttribute(attrSet, HTML.Tag.CONTENT))
772: {
773: writeEmbeddedTags(attrSet);
774:
775: int content_offset = paramElem.getStartOffset();
776: int content_length = currElem.getEndOffset() - content_offset;
777:
778: if (doc_offset_remaining > 0)
779: {
780: if (content_length > doc_offset_remaining)
781: {
782: int split_len = content_length;
783:
784: split_len = split_len - doc_offset_remaining;
785:
786: if (split_len > doc_len_remaining)
787: split_len = doc_len_remaining;
788:
789:
790: String txt_value = htmlDoc.getText(content_offset
791: + doc_offset_remaining, split_len);
792:
793: writeContent(txt_value);
794:
795: doc_offset_remaining = 0;
796: doc_len_remaining = doc_len_remaining - split_len;
797: }
798: else
799: {
800:
801:
802: doc_offset_remaining = doc_offset_remaining
803: - content_length;
804: }
805: }
806: else if (content_length <= doc_len_remaining)
807: {
808:
809: text(currElem);
810: doc_len_remaining = doc_len_remaining - content_length;
811: }
812: else
813: {
814:
815: String txt_value = htmlDoc.getText(content_offset,
816: doc_len_remaining);
817:
818: writeContent(txt_value);
819:
820: doc_len_remaining = 0;
821: }
822:
823: }
824: else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT))
825: {
826: comment(currElem);
827: }
828: else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
829: {
830: int child_elem_count = currElem.getElementCount();
831:
832: if (child_elem_count > 0)
833: {
834: for (int i = 0; i < child_elem_count; i++)
835: {
836: Element childElem = paramElem.getElement(i);
837:
838: traverseHtmlFragment(childElem);
839:
840: }
841: }
842: }
843: }
844: else
845: {
846:
847:
848: if (paramElem.isLeaf())
849: {
850: if (doc_offset_remaining > 0)
851: {
852: doc_offset_remaining--;
853: }
854: else if (doc_len_remaining > 0)
855: {
856: doc_len_remaining--;
857: }
858: }
859:
860:
861:
862: if (matchNameAttribute(attrSet, HTML.Tag.TITLE))
863: {
864: boolean fg_is_end_tag = false;
865: Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
866:
867: while (attrNameEnum.hasMoreElements())
868: {
869: Object key = attrNameEnum.nextElement();
870: Object value = attrSet.getAttribute(key);
871:
872: if (key == HTML.Attribute.ENDTAG && value.equals("true"))
873: fg_is_end_tag = true;
874: }
875:
876: if (fg_is_end_tag)
877: writeRaw("</title>");
878: else
879: {
880: indent();
881: writeRaw("<title>");
882:
883: String title_str =
884: (String) htmlDoc.getProperty(HTMLDocument.TitleProperty);
885:
886: if (title_str != null)
887: writeContent(title_str);
888:
889: }
890: }
891: else if (matchNameAttribute(attrSet, HTML.Tag.PRE))
892: {
893:
894: attrSet = paramElem.getAttributes();
895:
896: indent();
897: writeRaw("<pre");
898: writeAttributes(attrSet);
899: writeRaw(">");
900:
901: int child_elem_count = currElem.getElementCount();
902:
903: for (int i = 0; i < child_elem_count; i++)
904: {
905: Element childElem = paramElem.getElement(i);
906:
907: traverseHtmlFragment(childElem);
908:
909: }
910:
911: writeRaw("</pre>");
912:
913: }
914: else if (matchNameAttribute(attrSet, HTML.Tag.SELECT))
915: {
916: selectContent(attrSet);
917: }
918: else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
919: {
920: textAreaContent(attrSet);
921: }
922: else
923: {
924: int child_elem_count = currElem.getElementCount();
925:
926: if (child_elem_count > 0)
927: {
928: startTag(currElem);
929:
930: for (int i = 0; i < child_elem_count; i++)
931: {
932: Element childElem = paramElem.getElement(i);
933:
934: traverseHtmlFragment(childElem);
935:
936: }
937:
938: endTag(currElem);
939:
940: }
941: else
942: {
943: emptyTag(currElem);
944: }
945: }
946: }
947:
948: }
949:
950:
951: if (paramElem == endElem)
952: fg_pass_end_elem = true;
953:
954: }
955:
956:
957:
964: private void writeRaw(String param_str)
965: throws IOException
966: {
967: super.output(param_str.toCharArray(), 0, param_str.length());
968: }
969:
970:
971:
978: private void writeContent(String param_str)
979: throws IOException
980: {
981: char[] str_char_arr = param_str.toCharArray();
982:
983: if (hasHtmlEntity(param_str))
984: output(str_char_arr, 0, str_char_arr.length);
985: else
986: super.output(str_char_arr, 0, str_char_arr.length);
987:
988: }
989:
990:
998: private void writeAllAttributes(AttributeSet attrSet)
999: throws IOException
1000: {
1001: Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
1002:
1003: while (attrNameEnum.hasMoreElements())
1004: {
1005: Object key = attrNameEnum.nextElement();
1006: Object value = attrSet.getAttribute(key);
1007:
1008: writeRaw(" " + key + "=\"" + value + "\"");
1009: writeRaw(" " + key.getClass().toString() + "=\""
1010: + value.getClass().toString() + "\"");
1011: }
1012:
1013: }
1014:
1015:
1016:
1024: private boolean hasHtmlEntity(String param_str)
1025: {
1026: boolean ret_bool = false;
1027:
1028: for (int i = 0; i < html_entity_char_arr.length; i++)
1029: {
1030: if (param_str.indexOf(html_entity_char_arr[i]) != -1)
1031: {
1032: ret_bool = true;
1033: break;
1034: }
1035: }
1036:
1037: return ret_bool;
1038: }
1039:
1040:
1048: private boolean isCharHtmlEntity(char param_char)
1049: {
1050: boolean ret_bool = false;
1051:
1052: for (int i = 0; i < html_entity_char_arr.length; i++)
1053: {
1054: if (param_char == html_entity_char_arr[i])
1055: {
1056: ret_bool = true;
1057: break;
1058: }
1059: }
1060:
1061: return ret_bool;
1062: }
1063:
1064:
1072: private String escapeCharHtmlEntity(char param_char)
1073: {
1074: String ret_str = "" + param_char;
1075:
1076: for (int i = 0; i < html_entity_char_arr.length; i++)
1077: {
1078: if (param_char == html_entity_char_arr[i])
1079: {
1080: ret_str = html_entity_escape_str_arr[i];
1081: break;
1082: }
1083: }
1084:
1085: return ret_str;
1086: }
1087:
1088: }