1 3 package com.nwalsh.xalan; 4 5 import java.util.Stack ; 6 import java.util.StringTokenizer ; 7 8 import org.xml.sax.*; 9 import org.xml.sax.helpers.AttributesImpl ; 10 import org.w3c.dom.*; 11 import org.w3c.dom.traversal.NodeIterator; 12 import org.apache.xerces.dom.*; 13 14 import org.apache.xpath.objects.XObject; 15 import org.apache.xpath.XPath; 16 import org.apache.xpath.XPathContext; 17 import org.apache.xpath.NodeSet; 18 import org.apache.xpath.DOMHelper; 19 import org.apache.xalan.extensions.XSLProcessorContext; 20 import org.apache.xalan.extensions.ExpressionContext; 21 import org.apache.xalan.transformer.TransformerImpl; 22 import org.apache.xalan.templates.StylesheetRoot; 23 import org.apache.xalan.templates.ElemExtensionCall; 24 import org.apache.xalan.templates.OutputProperties; 25 import org.apache.xalan.res.XSLTErrorResources; 26 import org.apache.xml.utils.DOMBuilder; 27 import org.apache.xml.utils.AttList; 28 import org.apache.xml.utils.QName; 29 30 import javax.xml.transform.stream.StreamResult ; 31 import javax.xml.transform.TransformerException ; 32 import javax.xml.parsers.DocumentBuilder ; 33 import javax.xml.parsers.DocumentBuilderFactory ; 34 import javax.xml.parsers.ParserConfigurationException ; 35 36 import com.nwalsh.xalan.Callout; 37 import com.nwalsh.xalan.Params; 38 39 78 public class Verbatim { 79 80 private Stack elementStack = null; 81 82 private Stack tempStack = null; 83 84 private int lineNumber = 0; 85 86 private int colNumber = 0; 87 88 private int modulus = 0; 89 90 private int width = 0; 91 92 private String separator = ""; 93 94 private Callout callout[] = null; 95 96 private int calloutCount = 0; 97 98 private int calloutPos = 0; 99 100 private String graphicsPath = null; 101 102 private String graphicsExt = null; 103 104 private int graphicsMax = 10; 105 106 private boolean graphicsFO = false; 107 108 private static final String foURI = "http://www.w3.org/1999/XSL/Format"; 109 private static final String xhURI = "http://www.w3.org/1999/xhtml"; 110 111 116 public Verbatim() { 117 } 118 119 158 public DocumentFragment numberLines (ExpressionContext context, 159 NodeIterator xalanNI) { 160 161 int xalanMod = Params.getInt(context, "linenumbering.everyNth"); 162 int xalanWidth = Params.getInt(context, "linenumbering.width"); 163 String xalanSep = Params.getString(context, "linenumbering.separator"); 164 165 DocumentFragment xalanRTF = (DocumentFragment) xalanNI.nextNode(); 166 int numLines = countLineBreaks(xalanRTF) + 1; 167 168 DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); 169 DocumentBuilder docBuilder = null; 170 171 try { 172 docBuilder = docFactory.newDocumentBuilder(); 173 } catch (ParserConfigurationException e) { 174 System.out.println("PCE!"); 175 return xalanRTF; 176 } 177 Document doc = docBuilder.newDocument(); 178 DocumentFragment df = doc.createDocumentFragment(); 179 DOMBuilder db = new DOMBuilder(doc, df); 180 181 elementStack = new Stack (); 182 lineNumber = 0; 183 modulus = numLines < xalanMod ? 1 : xalanMod; 184 width = xalanWidth; 185 separator = xalanSep; 186 187 double log10numLines = Math.log(numLines) / Math.log(10); 188 189 if (width < log10numLines + 1) { 190 width = (int) Math.floor(log10numLines + 1); 191 } 192 193 lineNumberFragment(db, xalanRTF); 194 return df; 195 } 196 197 205 private int countLineBreaks(Node node) { 206 int numLines = 0; 207 208 if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE 209 || node.getNodeType() == Node.DOCUMENT_NODE 210 || node.getNodeType() == Node.ELEMENT_NODE) { 211 Node child = node.getFirstChild(); 212 while (child != null) { 213 numLines += countLineBreaks(child); 214 child = child.getNextSibling(); 215 } 216 } else if (node.getNodeType() == Node.TEXT_NODE) { 217 String text = node.getNodeValue(); 218 219 int pos = 0; 221 for (int count = 0; count < text.length(); count++) { 222 if (text.charAt(count) == '\n') { 223 numLines++; 224 } 225 } 226 } else { 227 } 229 230 return numLines; 231 } 232 233 249 private void lineNumberFragment(DOMBuilder rtf, 250 Node node) { 251 try { 252 if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE 253 || node.getNodeType() == Node.DOCUMENT_NODE) { 254 Node child = node.getFirstChild(); 255 while (child != null) { 256 lineNumberFragment(rtf, child); 257 child = child.getNextSibling(); 258 } 259 } else if (node.getNodeType() == Node.ELEMENT_NODE) { 260 String ns = node.getNamespaceURI(); 261 String localName = node.getLocalName(); 262 String name = ((Element) node).getTagName(); 263 264 rtf.startElement(ns, localName, name, 265 copyAttributes((Element) node)); 266 267 elementStack.push(node); 268 269 Node child = node.getFirstChild(); 270 while (child != null) { 271 lineNumberFragment(rtf, child); 272 child = child.getNextSibling(); 273 } 274 } else if (node.getNodeType() == Node.TEXT_NODE) { 275 String text = node.getNodeValue(); 276 277 if (lineNumber == 0) { 278 formatLineNumber(rtf, ++lineNumber); 280 } 281 282 char chars[] = text.toCharArray(); 284 int pos = 0; 285 for (int count = 0; count < text.length(); count++) { 286 if (text.charAt(count) == '\n') { 287 290 if (pos > 0) { 291 rtf.characters(chars, 0, pos); 292 pos = 0; 293 } 294 295 closeOpenElements(rtf); 296 297 chars[pos++] = text.charAt(count); 299 rtf.characters(chars, 0, pos); 300 pos = 0; 301 302 formatLineNumber(rtf, ++lineNumber); 304 305 openClosedElements(rtf); 306 } else { 307 chars[pos++] = text.charAt(count); 308 } 309 } 310 311 if (pos > 0) { 312 rtf.characters(chars, 0, pos); 313 } 314 } else if (node.getNodeType() == Node.COMMENT_NODE) { 315 String text = node.getNodeValue(); 316 char chars[] = text.toCharArray(); 317 rtf.comment(chars, 0, text.length()); 318 } else if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { 319 rtf.processingInstruction(node.getNodeName(), node.getNodeValue()); 320 } else { 321 System.out.println("Warning: unexpected node type in lineNumberFragment"); 322 } 323 324 if (node.getNodeType() == Node.ELEMENT_NODE) { 325 String ns = node.getNamespaceURI(); 326 String localName = node.getLocalName(); 327 String name = ((Element) node).getTagName(); 328 rtf.endElement(ns, localName, name); 329 elementStack.pop(); 330 } 331 } catch (SAXException e) { 332 System.out.println("SAX Exception in lineNumberFragment"); 333 } 334 } 335 336 346 private void formatLineNumber(DOMBuilder rtf, 347 int lineNumber) { 348 char ch = 160; 349 String lno = ""; 350 if (lineNumber == 1 351 || (modulus >= 1 && (lineNumber % modulus == 0))) { 352 lno = "" + lineNumber; 353 } 354 355 while (lno.length() < width) { 356 lno = ch + lno; 357 } 358 359 lno += separator; 360 361 char chars[] = lno.toCharArray(); 362 try { 363 rtf.characters(chars, 0, lno.length()); 364 } catch (SAXException e) { 365 System.out.println("SAX Exception in formatLineNumber"); 366 } 367 } 368 369 397 398 443 444 public DocumentFragment insertCallouts (ExpressionContext context, 445 NodeIterator areaspecNodeSet, 446 NodeIterator xalanNI) { 447 String type = Params.getString(context, "stylesheet.result.type"); 448 boolean useFO = type.equals("fo"); 449 int defaultColumn = Params.getInt(context, "callout.defaultcolumn"); 450 451 if (Params.getBoolean(context, "callout.graphics")) { 452 String gPath = Params.getString(context, "callout.graphics.path"); 453 String gExt = Params.getString(context, "callout.graphics.extension"); 454 int gMax = Params.getInt(context, "callout.graphics.number.limit"); 455 return insertGraphicCallouts(areaspecNodeSet, xalanNI, defaultColumn, 456 gPath, gExt, gMax, useFO); 457 } else if (Params.getBoolean(context, "callout.unicode")) { 458 int uStart = Params.getInt(context, "callout.unicode.start.character"); 459 int uMax = Params.getInt(context, "callout.unicode.number.limit"); 460 String uFont = Params.getString(context, "callout.unicode.font"); 461 return insertUnicodeCallouts(areaspecNodeSet, xalanNI, defaultColumn, 462 uFont, uStart, uMax, useFO); 463 } else if (Params.getBoolean(context, "callout.dingbats")) { 464 int dMax = 10; 465 return insertDingbatCallouts(areaspecNodeSet, xalanNI, defaultColumn, 466 dMax, useFO); 467 } else { 468 return insertTextCallouts(areaspecNodeSet, xalanNI, defaultColumn, useFO); 469 } 470 } 471 472 public DocumentFragment insertGraphicCallouts (NodeIterator areaspecNodeSet, 473 NodeIterator xalanNI, 474 int defaultColumn, 475 String gPath, 476 String gExt, 477 int gMax, 478 boolean useFO) { 479 FormatGraphicCallout fgc = new FormatGraphicCallout(gPath,gExt,gMax,useFO); 480 return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn, fgc); 481 } 482 483 public DocumentFragment insertUnicodeCallouts (NodeIterator areaspecNodeSet, 484 NodeIterator xalanNI, 485 int defaultColumn, 486 String uFont, 487 int uStart, 488 int uMax, 489 boolean useFO) { 490 FormatUnicodeCallout fuc = new FormatUnicodeCallout(uFont, uStart, uMax, useFO); 491 return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn, fuc); 492 } 493 494 public DocumentFragment insertDingbatCallouts (NodeIterator areaspecNodeSet, 495 NodeIterator xalanNI, 496 int defaultColumn, 497 int gMax, 498 boolean useFO) { 499 FormatDingbatCallout fdc = new FormatDingbatCallout(gMax,useFO); 500 return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn, fdc); 501 } 502 503 public DocumentFragment insertTextCallouts (NodeIterator areaspecNodeSet, 504 NodeIterator xalanNI, 505 int defaultColumn, 506 boolean useFO) { 507 FormatTextCallout ftc = new FormatTextCallout(useFO); 508 return insertCallouts(areaspecNodeSet, xalanNI, defaultColumn, ftc); 509 } 510 511 public DocumentFragment insertCallouts (NodeIterator areaspecNodeSet, 512 NodeIterator xalanNI, 513 int defaultColumn, 514 FormatCallout fCallout) { 515 516 DocumentFragment xalanRTF = (DocumentFragment) xalanNI.nextNode(); 517 518 callout = new Callout[10]; 519 calloutCount = 0; 520 calloutPos = 0; 521 lineNumber = 1; 522 colNumber = 1; 523 524 int pos = 0; 535 int coNum = 0; 536 boolean inAreaSet = false; 537 Node node = areaspecNodeSet.nextNode(); 538 node = node.getFirstChild(); 539 while (node != null) { 540 if (node.getNodeType() == Node.ELEMENT_NODE) { 541 if (node.getNodeName().equals("areaset")) { 542 coNum++; 543 Node area = node.getFirstChild(); 544 while (area != null) { 545 if (area.getNodeType() == Node.ELEMENT_NODE) { 546 if (area.getNodeName().equals("area")) { 547 addCallout(coNum, area, defaultColumn); 548 } else { 549 System.out.println("Unexpected element in areaset: " 550 + area.getNodeName()); 551 } 552 } 553 area = area.getNextSibling(); 554 } 555 } else if (node.getNodeName().equalsIgnoreCase("area")) { 556 coNum++; 557 addCallout(coNum, node, defaultColumn); 558 } else { 559 System.out.println("Unexpected element in areaspec: " 560 + node.getNodeName()); 561 } 562 } 563 564 node = node.getNextSibling(); 565 } 566 567 java.util.Arrays.sort(callout, 0, calloutCount); 569 570 DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); 571 DocumentBuilder docBuilder = null; 572 573 try { 574 docBuilder = docFactory.newDocumentBuilder(); 575 } catch (ParserConfigurationException e) { 576 System.out.println("PCE 2!"); 577 return xalanRTF; 578 } 579 Document doc = docBuilder.newDocument(); 580 DocumentFragment df = doc.createDocumentFragment(); 581 DOMBuilder db = new DOMBuilder(doc, df); 582 583 elementStack = new Stack (); 584 calloutFragment(db, xalanRTF, fCallout); 585 return df; 586 } 587 588 604 private void calloutFragment(DOMBuilder rtf, 605 Node node, 606 FormatCallout fCallout) { 607 try { 608 if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE 609 || node.getNodeType() == Node.DOCUMENT_NODE) { 610 Node child = node.getFirstChild(); 611 while (child != null) { 612 calloutFragment(rtf, child, fCallout); 613 child = child.getNextSibling(); 614 } 615 } else if (node.getNodeType() == Node.ELEMENT_NODE) { 616 String ns = node.getNamespaceURI(); 617 String localName = node.getLocalName(); 618 String name = ((Element) node).getTagName(); 619 620 rtf.startElement(ns, localName, name, 621 copyAttributes((Element) node)); 622 623 elementStack.push(node); 624 625 Node child = node.getFirstChild(); 626 while (child != null) { 627 calloutFragment(rtf, child, fCallout); 628 child = child.getNextSibling(); 629 } 630 } else if (node.getNodeType() == Node.TEXT_NODE) { 631 String text = node.getNodeValue(); 632 633 char chars[] = text.toCharArray(); 634 int pos = 0; 635 for (int count = 0; count < text.length(); count++) { 636 if (calloutPos < calloutCount 637 && callout[calloutPos].getLine() == lineNumber 638 && callout[calloutPos].getColumn() == colNumber) { 639 if (pos > 0) { 640 rtf.characters(chars, 0, pos); 641 pos = 0; 642 } 643 644 closeOpenElements(rtf); 645 646 while (calloutPos < calloutCount 647 && callout[calloutPos].getLine() == lineNumber 648 && callout[calloutPos].getColumn() == colNumber) { 649 fCallout.formatCallout(rtf, callout[calloutPos]); 650 calloutPos++; 651 } 652 653 openClosedElements(rtf); 654 } 655 656 if (text.charAt(count) == '\n') { 657 if (calloutPos < calloutCount 659 && callout[calloutPos].getLine() == lineNumber 660 && callout[calloutPos].getColumn() > colNumber) { 661 662 if (pos > 0) { 663 rtf.characters(chars, 0, pos); 664 pos = 0; 665 } 666 667 closeOpenElements(rtf); 668 669 while (calloutPos < calloutCount 670 && callout[calloutPos].getLine() == lineNumber 671 && callout[calloutPos].getColumn() > colNumber) { 672 formatPad(rtf, callout[calloutPos].getColumn() - colNumber); 673 colNumber = callout[calloutPos].getColumn(); 674 while (calloutPos < calloutCount 675 && callout[calloutPos].getLine() == lineNumber 676 && callout[calloutPos].getColumn() == colNumber) { 677 fCallout.formatCallout(rtf, callout[calloutPos]); 678 calloutPos++; 679 } 680 } 681 682 openClosedElements(rtf); 683 } 684 685 lineNumber++; 686 colNumber = 1; 687 } else { 688 colNumber++; 689 } 690 chars[pos++] = text.charAt(count); 691 } 692 693 if (pos > 0) { 694 rtf.characters(chars, 0, pos); 695 } 696 } else if (node.getNodeType() == Node.COMMENT_NODE) { 697 String text = node.getNodeValue(); 698 char chars[] = text.toCharArray(); 699 rtf.comment(chars, 0, text.length()); 700 } else if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { 701 rtf.processingInstruction(node.getNodeName(), node.getNodeValue()); 702 } else { 703 System.out.println("Warning: unexpected node type in calloutFragment: " + node.getNodeType() + ": " + node.getNodeName()); 704 } 705 706 if (node.getNodeType() == Node.ELEMENT_NODE) { 707 String ns = node.getNamespaceURI(); 708 String localName = node.getLocalName(); 709 String name = ((Element) node).getTagName(); 710 rtf.endElement(ns, localName, name); 711 elementStack.pop(); 712 } else { 713 } 715 } catch (SAXException e) { 716 System.out.println("SAX Exception in calloutFragment"); 717 } 718 } 719 720 735 private void addCallout (int coNum, 736 Node node, 737 int defaultColumn) { 738 Element area = (Element) node; 739 740 String units = area.getAttribute("units"); 741 String otherUnits = area.getAttribute("otherunits"); 742 String coords = area.getAttribute("coords"); 743 int type = 0; 744 String otherType = null; 745 746 if (units == null || units.equals("linecolumn")) { 747 type = Callout.LINE_COLUMN; } else if (units.equals("linerange")) { 749 type = Callout.LINE_RANGE; 750 } else if (units.equals("linecolumnpair")) { 751 type = Callout.LINE_COLUMN_PAIR; 752 } else if (units.equals("calspair")) { 753 type = Callout.CALS_PAIR; 754 } else { 755 type = Callout.OTHER; 756 otherType = otherUnits; 757 } 758 759 if (type != Callout.LINE_COLUMN 760 && type != Callout.LINE_RANGE) { 761 System.out.println("Only linecolumn and linerange units are supported"); 762 return; 763 } 764 765 if (coords == null) { 766 System.out.println("Coords must be specified"); 767 return; 768 } 769 770 StringTokenizer st = new StringTokenizer (coords); 772 int tokenCount = 0; 773 int c1 = 0; 774 int c2 = 0; 775 while (st.hasMoreTokens()) { 776 tokenCount++; 777 if (tokenCount > 2) { 778 System.out.println("Unparseable coordinates"); 779 return; 780 } 781 try { 782 String token = st.nextToken(); 783 int coord = Integer.parseInt(token); 784 c2 = coord; 785 if (tokenCount == 1) { 786 c1 = coord; 787 } 788 } catch (NumberFormatException e) { 789 System.out.println("Unparseable coordinate"); 790 return; 791 } 792 } 793 794 if (calloutCount == callout.length) { 796 Callout bigger[] = new Callout[calloutCount+10]; 797 for (int count = 0; count < callout.length; count++) { 798 bigger[count] = callout[count]; 799 } 800 callout = bigger; 801 } 802 803 if (tokenCount == 2) { 805 if (type == Callout.LINE_RANGE) { 806 for (int count = c1; count <= c2; count++) { 807 callout[calloutCount++] = new Callout(coNum, area, 808 count, defaultColumn, 809 type); 810 } 811 } else { 812 callout[calloutCount++] = new Callout(coNum, area, c1, c2, type); 814 } 815 } else { 816 callout[calloutCount++] = new Callout(coNum, area, c1, defaultColumn, type); 818 } 819 } 820 821 831 private void formatPad(DOMBuilder rtf, 832 int numBlanks) { 833 char chars[] = new char[numBlanks]; 834 for (int count = 0; count < numBlanks; count++) { 835 chars[count] = ' '; 836 } 837 838 try { 839 rtf.characters(chars, 0, numBlanks); 840 } catch (SAXException e) { 841 System.out.println("SAX Exception in formatCallout"); 842 } 843 } 844 845 private void closeOpenElements(DOMBuilder rtf) 846 throws SAXException { 847 tempStack = new Stack (); 849 while (!elementStack.empty()) { 850 Node elem = (Node) elementStack.pop(); 851 852 String ns = elem.getNamespaceURI(); 853 String localName = elem.getLocalName(); 854 String name = ((Element) elem).getTagName(); 855 856 if (elementStack.empty() 859 && (((ns != null) 860 && ns.equals(foURI) 861 && localName.equals("block")) 862 || (((ns == null) 863 && localName.equalsIgnoreCase("pre")) 864 || ((ns != null) 865 && ns.equals(xhURI) 866 && localName.equals("pre"))) 867 || (((ns == null) 868 && localName.equalsIgnoreCase("div")) 869 || ((ns != null) 870 && ns.equals(xhURI) 871 && localName.equals("div"))))) { 872 elementStack.push(elem); 873 break; 874 } else { 875 rtf.endElement(ns, localName, name); 876 tempStack.push(elem); 877 } 878 } 879 } 880 881 private void openClosedElements(DOMBuilder rtf) 882 throws SAXException { 883 while (!tempStack.empty()) { 885 Node elem = (Node) tempStack.pop(); 886 887 String ns = elem.getNamespaceURI(); 888 String localName = elem.getLocalName(); 889 String name = ((Element) elem).getTagName(); 890 NamedNodeMap domAttr = elem.getAttributes(); 891 892 AttributesImpl attr = new AttributesImpl (); 893 for (int acount = 0; acount < domAttr.getLength(); acount++) { 894 Node a = domAttr.item(acount); 895 896 if (((ns == null || ns == "http://www.w3.org/1999/xhtml") 897 && localName.equalsIgnoreCase("a")) 898 || (a.getLocalName().equalsIgnoreCase("id"))) { 899 } else { 901 attr.addAttribute(a.getNamespaceURI(), 902 a.getLocalName(), 903 a.getNodeName(), 904 "CDATA", 905 a.getNodeValue()); 906 } 907 } 908 909 rtf.startElement(ns, localName, name, attr); 910 elementStack.push(elem); 911 } 912 913 tempStack = null; 914 } 915 916 private Attributes copyAttributes(Element node) { 917 AttributesImpl attrs = new AttributesImpl (); 918 NamedNodeMap nnm = node.getAttributes(); 919 for (int count = 0; count < nnm.getLength(); count++) { 920 Attr attr = (Attr) nnm.item(count); 921 String name = attr.getName(); 922 if (name.startsWith("xmlns:") || name.equals("xmlns")) { 923 } else { 925 attrs.addAttribute(attr.getNamespaceURI(), attr.getName(), 926 attr.getName(), "CDATA", attr.getValue()); 927 } 928 } 929 return attrs; 930 } 931 } 932 | Popular Tags |