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