1 52 53 package freemarker.ext.jdom; 54 55 import java.io.FileReader ; 56 import java.io.IOException ; 57 import java.io.Writer ; 58 import java.util.ArrayList ; 59 import java.util.Collections ; 60 import java.util.HashMap ; 61 import java.util.HashSet ; 62 import java.util.Iterator ; 63 import java.util.LinkedList ; 64 import java.util.List ; 65 import java.util.Map ; 66 import java.util.Set ; 67 import java.util.WeakHashMap ; 68 69 import org.jaxen.Context; 70 import org.jaxen.JaxenException; 71 import org.jaxen.NamespaceContext; 72 import org.jaxen.jdom.JDOMXPath; 73 import org.jdom.Attribute; 74 import org.jdom.CDATA; 75 import org.jdom.Comment; 76 import org.jdom.DocType; 77 import org.jdom.Document; 78 import org.jdom.Element; 79 import org.jdom.EntityRef; 80 import org.jdom.Namespace; 81 import org.jdom.ProcessingInstruction; 82 import org.jdom.Text; 83 import org.jdom.output.XMLOutputter; 84 import freemarker.template.SimpleHash; 85 import freemarker.template.SimpleScalar; 86 import freemarker.template.Template; 87 import freemarker.template.TemplateCollectionModel; 88 import freemarker.template.TemplateHashModel; 89 import freemarker.template.TemplateMethodModel; 90 import freemarker.template.TemplateModel; 91 import freemarker.template.TemplateModelException; 92 import freemarker.template.TemplateModelIterator; 93 import freemarker.template.TemplateScalarModel; 94 import freemarker.template.TemplateSequenceModel; 95 import freemarker.template.utility.Collections12; 96 97 122 public class NodeListModel 123 implements 124 TemplateHashModel, 125 TemplateMethodModel, 126 TemplateCollectionModel, 127 TemplateSequenceModel, 128 TemplateScalarModel 129 { 130 private static final AttributeXMLOutputter OUTPUT = new AttributeXMLOutputter(); 131 private static final NodeListModel EMPTY = new NodeListModel(null, false); 133 134 private static final Map XPATH_CACHE = new WeakHashMap (); 136 137 private static final NamedNodeOperator NAMED_CHILDREN_OP = new NamedChildrenOp(); 138 private static final NamedNodeOperator NAMED_ATTRIBUTE_OP = new NamedAttributeOp(); 139 private static final NodeOperator ALL_ATTRIBUTES_OP = new AllAttributesOp(); 140 private static final NodeOperator ALL_CHILDREN_OP = new AllChildrenOp(); 141 private static final Map OPERATIONS = createOperations(); 142 private static final Map SPECIAL_OPERATIONS = createSpecialOperations(); 143 private static final int SPECIAL_OPERATION_COPY = 0; 144 private static final int SPECIAL_OPERATION_UNIQUE = 1; 145 private static final int SPECIAL_OPERATION_FILTER_NAME = 2; 146 private static final int SPECIAL_OPERATION_FILTER_TYPE = 3; 147 private static final int SPECIAL_OPERATION_QUERY_TYPE = 4; 148 private static final int SPECIAL_OPERATION_REGISTER_NAMESPACE = 5; 149 private static final int SPECIAL_OPERATION_PLAINTEXT = 6; 150 151 private final List nodes; 153 private final Map namespaces; 154 155 158 public NodeListModel(Document document) 159 { 160 nodes = document == null ? Collections.EMPTY_LIST : Collections12.singletonList(document); 161 namespaces = new HashMap (); 162 } 163 164 167 public NodeListModel(Element element) 168 { 169 nodes = element == null ? Collections.EMPTY_LIST : Collections12.singletonList(element); 170 namespaces = new HashMap (); 171 } 172 173 private NodeListModel(Object object, Map namespaces) 174 { 175 nodes = object == null ? Collections.EMPTY_LIST : Collections12.singletonList(object); 176 this.namespaces = namespaces; 177 } 178 179 185 public NodeListModel(List nodes) 186 { 187 this(nodes, true); 188 } 189 190 198 public NodeListModel(List nodes, boolean copy) 199 { 200 this.nodes = copy && nodes != null ? new ArrayList (nodes) : (nodes == null ? Collections.EMPTY_LIST : nodes); 201 namespaces = new HashMap (); 202 } 203 204 private NodeListModel(List nodes, Map namespaces) 205 { 206 this.nodes = nodes == null ? Collections.EMPTY_LIST : nodes; 207 this.namespaces = namespaces; 208 } 209 210 private static final NodeListModel createNodeListModel(List list, Map namespaces) 211 { 212 if (list == null || list.isEmpty()) { 213 if (namespaces.isEmpty()) { 214 return EMPTY; 215 } else { 216 return new NodeListModel(Collections.EMPTY_LIST, namespaces); 217 } 218 } 219 if (list.size() == 1) return new NodeListModel(list.get(0), namespaces); 220 return new NodeListModel(list, namespaces); 221 } 222 223 226 public boolean isEmpty() 227 { 228 return nodes.isEmpty(); 229 } 230 231 238 public String getAsString() 239 throws 240 TemplateModelException 241 { 242 if (isEmpty()) 243 return ""; 244 245 java.io.StringWriter sw = new java.io.StringWriter (nodes.size() * 128); 246 try { 247 for (Iterator i = nodes.iterator(); i.hasNext();) { 248 Object node = i.next(); 249 if (node instanceof Element) 250 OUTPUT.output((Element)node, sw); 251 else if (node instanceof Attribute) 252 OUTPUT.output((Attribute)node, sw); 253 else if (node instanceof String ) 254 sw.write(OUTPUT.escapeElementEntities(node.toString())); 255 else if (node instanceof Text) 256 OUTPUT.output((Text)node, sw); 257 else if (node instanceof Document) 258 OUTPUT.output((Document)node, sw); 259 else if (node instanceof ProcessingInstruction) 260 OUTPUT.output((ProcessingInstruction)node, sw); 261 else if (node instanceof Comment) 262 OUTPUT.output((Comment)node, sw); 263 else if (node instanceof CDATA) 264 OUTPUT.output((CDATA)node, sw); 265 else if (node instanceof DocType) 266 OUTPUT.output((DocType)node, sw); 267 else if (node instanceof EntityRef) 268 OUTPUT.output((EntityRef)node, sw); 269 else 270 throw new TemplateModelException(node.getClass().getName() + " is not a core JDOM class"); 271 } 272 } catch (IOException e) { 273 throw new TemplateModelException(e.getMessage()); 274 } 275 return sw.toString(); 276 } 277 278 279 394 public TemplateModel get(String key) 395 throws 396 TemplateModelException 397 { 398 if (isEmpty()) 399 return EMPTY; 400 401 if (key == null || key.length() == 0) 402 throw new TemplateModelException("Invalid key [" + key + "]"); 403 404 NodeOperator op = null; 405 NamedNodeOperator nop = null; 406 String name = null; 407 408 switch (key.charAt(0)) { 409 case '@': 410 { 411 if (key.length() != 2 || key.charAt(1) != '*') { 412 nop = NAMED_ATTRIBUTE_OP; 414 name = key.substring(1); 415 } else 416 op = ALL_ATTRIBUTES_OP; 418 419 break; 420 } 421 case '*': 422 { 423 if (key.length() == 1) 424 op = ALL_CHILDREN_OP; 425 else 426 throw new TemplateModelException("Invalid key [" + key + "]"); 428 429 break; 430 } 431 case 'x': 432 case '_': 433 { 434 op = (NodeOperator)OPERATIONS.get(key); 435 if (op == null) { 436 Integer specop = (Integer )SPECIAL_OPERATIONS.get(key); 438 if (specop != null) { 439 switch (specop.intValue()) { 440 case SPECIAL_OPERATION_COPY: 441 { 442 synchronized(namespaces) 443 { 444 return new NodeListModel(nodes, (Map )((HashMap )namespaces).clone()); 445 } 446 } 447 case SPECIAL_OPERATION_UNIQUE: 448 return new NodeListModel(removeDuplicates(nodes), namespaces); 449 case SPECIAL_OPERATION_FILTER_NAME: 450 return new NameFilter(); 451 case SPECIAL_OPERATION_FILTER_TYPE: 452 return new TypeFilter(); 453 case SPECIAL_OPERATION_QUERY_TYPE: 454 return getType(); 455 case SPECIAL_OPERATION_REGISTER_NAMESPACE: 456 return new RegisterNamespace(); 457 case SPECIAL_OPERATION_PLAINTEXT: 458 return getPlainText(); 459 } 460 } 461 } 462 break; 463 } 464 } 465 466 if (op == null && nop == null) { 467 nop = NAMED_CHILDREN_OP; 468 name = key; 469 } 470 471 List list = null; 472 if (op != null) 473 list = evaluateElementOperation(op, nodes); 474 else { 475 String localName = name; 476 Namespace namespace = Namespace.NO_NAMESPACE; 477 int colon = name.indexOf(':'); 478 if (colon != -1) { 479 localName = name.substring(colon + 1); 480 String nsPrefix = name.substring(0, colon); 481 synchronized(namespaces) 482 { 483 namespace = (Namespace)namespaces.get(nsPrefix); 484 } 485 if (namespace == null) { 486 if (nsPrefix.equals("xml")) 487 namespace = Namespace.XML_NAMESPACE; 488 else 489 throw new TemplateModelException("Unregistered namespace prefix '" + nsPrefix + "'"); 490 } 491 } 492 493 list = evaluateNamedElementOperation(nop, localName, namespace, nodes); 494 } 495 return createNodeListModel(list, namespaces); 496 } 497 498 private TemplateModel getType() 499 { 500 if (nodes.size() == 0) 501 return new SimpleScalar(""); 502 Object firstNode = nodes.get(0); 503 char code; 504 if (firstNode instanceof Element) 505 code = 'e'; 506 else if (firstNode instanceof Text || firstNode instanceof String ) 507 code = 'x'; 508 else if (firstNode instanceof Attribute) 509 code = 'a'; 510 else if (firstNode instanceof EntityRef) 511 code = 'n'; 512 else if (firstNode instanceof Document) 513 code = 'd'; 514 else if (firstNode instanceof DocType) 515 code = 't'; 516 else if (firstNode instanceof Comment) 517 code = 'c'; 518 else if (firstNode instanceof ProcessingInstruction) 519 code = 'p'; 520 else 521 code = '?'; 522 return new SimpleScalar(new String (new char[] { code})); 523 } 524 525 private SimpleScalar getPlainText() 526 throws 527 TemplateModelException 528 { 529 List list = evaluateElementOperation((TextOp)OPERATIONS.get("_text"), nodes); 530 StringBuffer buf = new StringBuffer (); 531 for (Iterator it = list.iterator(); it.hasNext();) { 532 buf.append(it.next()); 533 } 534 return new SimpleScalar(buf.toString()); 535 } 536 537 public TemplateModelIterator iterator() 538 { 539 return new TemplateModelIterator() 540 { 541 private final Iterator it = nodes.iterator(); 542 543 public TemplateModel next() 544 { 545 return it.hasNext() ? new NodeListModel(it.next(), namespaces) : null; 546 } 547 548 public boolean hasNext() 549 { 550 return it.hasNext(); 551 } 552 }; 553 } 554 555 558 public TemplateModel get(int i) 559 throws 560 TemplateModelException 561 { 562 try { 563 return new NodeListModel(nodes.get(i), namespaces); 564 } catch (IndexOutOfBoundsException e) { 565 throw new TemplateModelException("Index out of bounds: " + e.getMessage()); 566 } 567 } 568 569 public int size() 570 { 571 return nodes.size(); 572 } 573 574 591 public Object exec(List arguments) 592 throws 593 TemplateModelException 594 { 595 if (arguments == null || arguments.size() != 1) 596 throw new TemplateModelException("Exactly one argument required for execute() on NodeTemplate"); 597 598 String xpathString = (String )arguments.get(0); 599 JDOMXPathEx xpath = null; 600 try 601 { 602 synchronized(XPATH_CACHE) 603 { 604 xpath = (JDOMXPathEx)XPATH_CACHE.get(xpathString); 605 if (xpath == null) 606 { 607 xpath = new JDOMXPathEx(xpathString); 608 XPATH_CACHE.put(xpathString, xpath); 609 } 610 } 611 return createNodeListModel(xpath.selectNodes(nodes, namespaces), namespaces); 612 } 613 catch(Exception e) 614 { 615 throw new TemplateModelException("Could not evaulate XPath expression " + xpathString, e); 616 } 617 } 618 619 644 public void registerNamespace(String prefix, String uri) 645 { 646 synchronized(namespaces) 647 { 648 namespaces.put(prefix, Namespace.getNamespace(prefix, uri)); 649 } 650 } 651 652 private interface NodeOperator { 653 List operate(Object node) 654 throws 655 TemplateModelException; 656 } 657 658 private interface NamedNodeOperator { 659 List operate(Object node, String localName, Namespace namespace) 660 throws 661 TemplateModelException; 662 } 663 664 private static final class AllChildrenOp implements NodeOperator { 665 public List operate(Object node) 666 { 667 if (node instanceof Element) 668 return((Element)node).getChildren(); 669 else if (node instanceof Document) { 670 Element root = ((Document)node).getRootElement(); 671 return root == null ? Collections.EMPTY_LIST : Collections12.singletonList(root); 672 } 673 return null; 676 680 } 681 } 682 683 private static final class NamedChildrenOp implements NamedNodeOperator { 684 public List operate(Object node, String localName, Namespace namespace) 685 { 686 if (node instanceof Element) { 687 return((Element)node).getChildren(localName, namespace); 688 } else if (node instanceof Document) { 689 Element root = ((Document)node).getRootElement(); 690 if (root != null && 691 root.getName().equals(localName) && 692 root.getNamespaceURI().equals(namespace.getURI())) { 693 return Collections12.singletonList(root); 694 } else 695 return Collections.EMPTY_LIST; 696 } 697 return null; 700 704 } 705 } 706 707 private static final class AllAttributesOp implements NodeOperator { 708 public List operate(Object node) 709 { 710 if (!(node instanceof Element)) { 713 return null; 714 } 715 return ((Element)node).getAttributes(); 716 720 } 721 } 722 723 private static final class NamedAttributeOp implements NamedNodeOperator { 724 public List operate(Object node, String localName, Namespace namespace) 725 { 726 Attribute attr = null; 727 if (node instanceof Element) { 728 Element element = (Element)node; 729 attr = element.getAttribute(localName, namespace); 730 } else if (node instanceof ProcessingInstruction) { 731 ProcessingInstruction pi = (ProcessingInstruction)node; 732 if ("target".equals(localName)) 733 attr = new Attribute("target", pi.getTarget()); 734 else if ("data".equals(localName)) 735 attr = new Attribute("data", pi.getData()); 736 else 737 attr = new Attribute(localName, pi.getValue(localName)); 738 } else if (node instanceof DocType) { 739 DocType doctype = (DocType)node; 740 if ("publicId".equals(localName)) 741 attr = new Attribute("publicId", doctype.getPublicID()); 742 else if ("systemId".equals(localName)) 743 attr = new Attribute("systemId", doctype.getSystemID()); 744 else if ("elementName".equals(localName)) 745 attr = new Attribute("elementName", doctype.getElementName()); 746 } 747 else { 750 return null; 751 } 752 756 return attr == null ? Collections.EMPTY_LIST : Collections12.singletonList(attr); 757 } 758 } 759 760 private static final class NameOp implements NodeOperator { 761 public List operate(Object node) 762 { 763 if (node instanceof Element) 764 return Collections12.singletonList(((Element)node).getName()); 765 else if (node instanceof Attribute) 766 return Collections12.singletonList(((Attribute)node).getName()); 767 else if (node instanceof EntityRef) 768 return Collections12.singletonList(((EntityRef)node).getName()); 769 else if (node instanceof ProcessingInstruction) 770 return Collections12.singletonList(((ProcessingInstruction)node).getTarget()); 771 else if (node instanceof DocType) 772 return Collections12.singletonList(((DocType)node).getPublicID()); 773 else 774 return null; 775 } 779 } 780 781 private static final class QNameOp implements NodeOperator { 782 public List operate(Object node) 783 { 784 if (node instanceof Element) 785 return Collections12.singletonList(((Element)node).getQualifiedName()); 786 else if (node instanceof Attribute) 787 return Collections12.singletonList(((Attribute)node).getQualifiedName()); 788 return null; 791 } 793 } 794 795 private static final class NamespaceUriOp implements NodeOperator { 796 public List operate(Object node) 797 { 798 if (node instanceof Element) 799 return Collections12.singletonList(((Element)node).getNamespace().getURI()); 800 else if (node instanceof Attribute) 801 return Collections12.singletonList(((Attribute)node).getNamespace().getURI()); 802 return null; 805 } 807 } 808 809 private static final class NamespacePrefixOp implements NodeOperator { 810 public List operate(Object node) 811 { 812 if (node instanceof Element) 813 return Collections12.singletonList(((Element)node).getNamespace().getPrefix()); 814 else if (node instanceof Attribute) 815 return Collections12.singletonList(((Attribute)node).getNamespace().getPrefix()); 816 return null; 819 } 821 } 822 823 private static final class CanonicalNameOp implements NodeOperator { 824 public List operate(Object node) 825 { 826 if (node instanceof Element) 827 { 828 Element element = (Element)node; 829 return Collections12.singletonList(element.getNamespace().getURI() + element.getName()); 830 } 831 else if (node instanceof Attribute) 832 { 833 Attribute attribute = (Attribute)node; 834 return Collections12.singletonList(attribute.getNamespace().getURI() + attribute.getName()); 835 } 836 return null; 839 } 841 } 842 843 844 private static final Element getParent(Object node) 845 { 846 if (node instanceof Element) 847 return((Element)node).getParent(); 848 else if (node instanceof Attribute) 849 return((Attribute)node).getParent(); 850 else if (node instanceof Text) 851 return((Text)node).getParent(); 852 else if (node instanceof ProcessingInstruction) 853 return((ProcessingInstruction)node).getParent(); 854 else if (node instanceof Comment) 855 return((Comment)node).getParent(); 856 else if (node instanceof EntityRef) 857 return((EntityRef)node).getParent(); 858 else 859 return null; 862 } 864 865 private static final class ParentOp implements NodeOperator { 866 public List operate(Object node) 867 { 868 Element parent = getParent(node); 869 return parent == null ? Collections.EMPTY_LIST : Collections12.singletonList(parent); 870 } 871 } 872 873 private static final class AncestorOp implements NodeOperator { 874 public List operate(Object node) 875 { 876 Element parent = getParent(node); 877 if (parent == null) return Collections.EMPTY_LIST; 878 LinkedList list = new LinkedList (); 879 do { 880 list.addFirst(parent); 881 parent = parent.getParent(); 882 } 883 while (parent != null); 884 return list; 885 } 886 } 887 888 private static final class AncestorOrSelfOp implements NodeOperator { 889 public List operate(Object node) 890 { 891 Element parent = getParent(node); 892 if (parent == null) return Collections12.singletonList(node); 893 LinkedList list = new LinkedList (); 894 list.addFirst(node); 895 do { 896 list.addFirst(parent); 897 parent = parent.getParent(); 898 } 899 while (parent != null); 900 return list; 901 } 902 } 903 904 private static class DescendantOp implements NodeOperator { 905 public List operate(Object node) 906 { 907 LinkedList list = new LinkedList (); 908 if (node instanceof Element) { 909 addChildren((Element)node, list); 910 } 911 else if (node instanceof Document) { 912 Element root = ((Document)node).getRootElement(); 913 list.add(root); 914 addChildren(root, list); 915 } 916 else 917 return null; 920 922 return list; 923 } 924 925 private void addChildren(Element element, List list) 926 { 927 List children = element.getChildren(); 928 Iterator it = children.iterator(); 929 while (it.hasNext()) { 930 Element child = (Element)it.next(); 931 list.add(child); 932 addChildren(child, list); 933 } 934 } 935 } 936 937 private static final class DescendantOrSelfOp extends DescendantOp { 938 public List operate(Object node) 939 { 940 LinkedList list = (LinkedList )super.operate(node); 941 list.addFirst(node); 942 return list; 943 } 944 } 945 946 private static final class DocumentOp implements NodeOperator { 947 public List operate(Object node) 948 { 949 Document doc = null; 950 if (node instanceof Element) 951 doc = ((Element)node).getDocument(); 952 else if (node instanceof Attribute) { 953 Element parent = ((Attribute)node).getParent(); 954 doc = parent == null ? null : parent.getDocument(); 955 } else if (node instanceof Text) { 956 Element parent = ((Text)node).getParent(); 957 doc = parent == null ? null : parent.getDocument(); 958 } else if (node instanceof Document) 959 doc = (Document)node; 960 else if (node instanceof ProcessingInstruction) 961 doc = ((ProcessingInstruction)node).getDocument(); 962 else if (node instanceof EntityRef) 963 doc = ((EntityRef)node).getDocument(); 964 else if (node instanceof Comment) 965 doc = ((Comment)node).getDocument(); 966 else 967 return null; 970 972 return doc == null ? Collections.EMPTY_LIST : Collections12.singletonList(doc); 973 } 974 } 975 976 private static final class DocTypeOp implements NodeOperator { 977 public List operate(Object node) 978 { 979 if (node instanceof Document) { 980 DocType doctype = ((Document)node).getDocType(); 981 return doctype == null ? Collections.EMPTY_LIST : Collections12.singletonList(doctype); 982 } else 983 return null; 986 } 988 } 989 990 private static final class ContentOp implements NodeOperator { 991 public List operate(Object node) 992 { 993 if (node instanceof Element) 994 return((Element)node).getContent(); 995 else if (node instanceof Document) 996 return((Document)node).getContent(); 997 return null; 1000 } 1002 } 1003 1004 private static final class TextOp implements NodeOperator { 1005 public List operate(Object node) 1006 { 1007 if (node instanceof Element) 1008 return Collections12.singletonList(((Element)node).getTextTrim()); 1009 if (node instanceof Attribute) 1010 return Collections12.singletonList(((Attribute)node).getValue()); 1011 if (node instanceof CDATA) 1012 return Collections12.singletonList(((CDATA)node).getText()); 1013 if (node instanceof Comment) 1014 return Collections12.singletonList(((Comment)node).getText()); 1015 if (node instanceof ProcessingInstruction) 1016 return Collections12.singletonList(((ProcessingInstruction)node).getData()); 1017 return null; 1020 } 1022 } 1023 1024 private static final List evaluateElementOperation(NodeOperator op, List nodes) 1025 throws 1026 TemplateModelException 1027 { 1028 int s = nodes.size(); 1029 List [] lists = new List [s]; 1030 int l = 0; 1031 { 1032 int i = 0; 1033 Iterator it = nodes.iterator(); 1034 while (it.hasNext()) { 1035 List list = op.operate(it.next()); 1036 if (list != null) { 1037 lists[i++] = list; 1038 l += list.size(); 1039 } 1040 } 1041 } 1042 List retval = new ArrayList (l); 1043 for (int i = 0; i < s; ++i) { 1044 if (lists[i] != null) { 1045 retval.addAll(lists[i]); 1046 } 1047 } 1048 return retval; 1049 } 1050 1051 private static final List evaluateNamedElementOperation(NamedNodeOperator op, String localName, Namespace namespace, List nodes) 1052 throws 1053 TemplateModelException 1054 { 1055 int s = nodes.size(); 1056 List [] lists = new List [s]; 1057 int l = 0; 1058 { 1059 int i = 0; 1060 Iterator it = nodes.iterator(); 1061 while (it.hasNext()) { 1062 List list = op.operate(it.next(), localName, namespace); 1063 lists[i++] = list; 1064 l += list.size(); 1065 } 1066 } 1067 List retval = new ArrayList (l); 1068 for (int i = 0; i < s; ++i) 1069 retval.addAll(lists[i]); 1070 return retval; 1071 } 1072 1073 private static final List removeDuplicates(List list) 1074 { 1075 int s = list.size(); 1076 ArrayList ulist = new ArrayList (s); 1077 Set set = new HashSet (s * 4 / 3, .75f); 1078 Iterator it = list.iterator(); 1079 while (it.hasNext()) { 1080 Object o = it.next(); 1081 if (set.add(o)) 1082 ulist.add(o); 1083 } 1084 ulist.trimToSize(); 1085 return ulist; 1086 } 1087 1088 private static final Map createOperations() 1089 { 1090 Map map = new HashMap (); 1091 1092 map.put("_ancestor", new AncestorOp()); 1093 map.put("_ancestorOrSelf", new AncestorOrSelfOp()); 1094 map.put("_attributes", ALL_ATTRIBUTES_OP); 1095 map.put("_children", ALL_CHILDREN_OP); 1096 map.put("_cname", new CanonicalNameOp()); 1097 map.put("_content", new ContentOp()); 1098 map.put("_descendant", new DescendantOp()); 1099 map.put("_descendantOrSelf", new DescendantOrSelfOp()); 1100 map.put("_document", new DocumentOp()); 1101 map.put("_doctype", new DocTypeOp()); 1102 map.put("_name", new NameOp()); 1103 map.put("_nsprefix", new NamespacePrefixOp()); 1104 map.put("_nsuri", new NamespaceUriOp()); 1105 map.put("_parent", new ParentOp()); 1106 map.put("_qname", new QNameOp()); 1107 map.put("_text", new TextOp()); 1108 1109 return map; 1110 } 1111 1112 private static final Map createSpecialOperations() 1113 { 1114 Map map = new HashMap (); 1115 1116 Integer copy = new Integer (SPECIAL_OPERATION_COPY); 1117 Integer unique = new Integer (SPECIAL_OPERATION_UNIQUE); 1118 Integer fname = new Integer (SPECIAL_OPERATION_FILTER_NAME); 1119 Integer ftype = new Integer (SPECIAL_OPERATION_FILTER_TYPE); 1120 Integer type = new Integer (SPECIAL_OPERATION_QUERY_TYPE); 1121 Integer regns = new Integer (SPECIAL_OPERATION_REGISTER_NAMESPACE); 1122 Integer plaintext = new Integer (SPECIAL_OPERATION_PLAINTEXT); 1123 1124 map.put("_copy", copy); 1125 map.put("_unique", unique); 1126 map.put("_fname", fname); 1127 map.put("_ftype", ftype); 1128 map.put("_type", type); 1129 map.put("_registerNamespace", regns); 1130 map.put("_plaintext", plaintext); 1131 1132 map.put("x_copy", copy); 1134 map.put("x_unique", unique); 1135 map.put("x_fname", fname); 1136 map.put("x_ftype", ftype); 1137 map.put("x_type", type); 1138 1139 return map; 1140 } 1141 1142 private final class RegisterNamespace implements TemplateMethodModel { 1143 public boolean isEmpty() 1144 { 1145 return false; 1146 } 1147 1148 public Object exec(List arguments) 1149 throws 1150 TemplateModelException 1151 { 1152 if (arguments.size() != 2) 1153 throw new TemplateModelException("_registerNamespace(prefix, uri) requires two arguments"); 1154 1155 registerNamespace((String )arguments.get(0), (String )arguments.get(1)); 1156 1157 return TemplateScalarModel.EMPTY_STRING; 1158 } 1159 } 1160 1161 private final class NameFilter implements TemplateMethodModel { 1162 public boolean isEmpty() 1163 { 1164 return false; 1165 } 1166 1167 public Object exec(List arguments) 1168 { 1169 Set names = new HashSet (arguments); 1170 List list = new LinkedList (nodes); 1171 Iterator it = list.iterator(); 1172 while (it.hasNext()) { 1173 Object node = it.next(); 1174 String name = null; 1175 if (node instanceof Element) 1176 name = ((Element)node).getName(); 1177 else if (node instanceof Attribute) 1178 name = ((Attribute)node).getName(); 1179 else if (node instanceof ProcessingInstruction) 1180 name = ((ProcessingInstruction)node).getTarget(); 1181 else if (node instanceof EntityRef) 1182 name = ((EntityRef)node).getName(); 1183 else if (node instanceof DocType) 1184 name = ((DocType)node).getPublicID(); 1185 1186 if (name == null || !names.contains(name)) 1187 it.remove(); 1188 } 1189 return createNodeListModel(list, namespaces); 1190 } 1191 } 1192 1193 private final class TypeFilter implements TemplateMethodModel { 1194 public boolean isEmpty() 1195 { 1196 return false; 1197 } 1198 1199 public Object exec(List arguments) 1200 throws 1201 TemplateModelException 1202 { 1203 if (arguments == null || arguments.size() == 0) 1204 throw new TemplateModelException("_type expects exactly one argument"); 1205 String arg = (String )arguments.get(0); 1206 boolean invert = arg.indexOf('!') != -1; 1207 boolean a = invert != (arg.indexOf('a') == -1); 1211 boolean c = invert != (arg.indexOf('c') == -1); 1212 boolean d = invert != (arg.indexOf('d') == -1); 1213 boolean e = invert != (arg.indexOf('e') == -1); 1214 boolean n = invert != (arg.indexOf('n') == -1); 1215 boolean p = invert != (arg.indexOf('p') == -1); 1216 boolean t = invert != (arg.indexOf('t') == -1); 1217 boolean x = invert != (arg.indexOf('x') == -1); 1218 1219 LinkedList list = new LinkedList (nodes); 1220 Iterator it = list.iterator(); 1221 while (it.hasNext()) { 1222 Object node = it.next(); 1223 if ((node instanceof Element && e) 1224 || (node instanceof Attribute && a) 1225 || (node instanceof String && x) 1226 || (node instanceof Text && x) 1227 || (node instanceof ProcessingInstruction && p) 1228 || (node instanceof Comment && c) 1229 || (node instanceof EntityRef && n) 1230 || (node instanceof Document && d) 1231 || (node instanceof DocType && t)) 1232 it.remove(); 1233 } 1234 return createNodeListModel(list, namespaces); 1235 } 1236 } 1237 1238 1244 public static void main(String [] args) 1245 throws 1246 Exception 1247 { 1248 org.jdom.input.SAXBuilder builder = new org.jdom.input.SAXBuilder(); 1249 Document document = builder.build(System.in); 1250 SimpleHash model = new SimpleHash(); 1251 model.put("document", new NodeListModel(document)); 1252 FileReader fr = new FileReader (args[0]); 1253 Template template = new Template(args[0], fr); 1254 Writer w = new java.io.OutputStreamWriter (System.out); 1255 template.process(model, w); 1256 w.flush(); 1257 w.close(); 1258 } 1259 1260 private static final class AttributeXMLOutputter extends XMLOutputter { 1261 public void output(Attribute attribute, Writer out) 1262 throws 1263 IOException 1264 { 1265 out.write(" "); 1266 out.write(attribute.getQualifiedName()); 1267 out.write("="); 1268 1269 out.write("\""); 1270 out.write(escapeAttributeEntities(attribute.getValue())); 1271 out.write("\""); 1272 } 1273 } 1274 1275 private static final class JDOMXPathEx 1276 extends 1277 JDOMXPath 1278 { 1279 JDOMXPathEx(String path) 1280 throws 1281 JaxenException 1282 { 1283 super(path); 1284 } 1285 1286 public List selectNodes(Object object, Map namespaces) 1287 throws 1288 JaxenException 1289 { 1290 Context context = getContext(object); 1291 context.getContextSupport().setNamespaceContext(new NamespaceContextImpl(namespaces)); 1292 return selectNodesForContext(context); 1293 } 1294 1295 private static final class NamespaceContextImpl 1296 implements 1297 NamespaceContext 1298 { 1299 private final Map namespaces; 1300 1301 NamespaceContextImpl(Map namespaces) 1302 { 1303 this.namespaces = namespaces; 1304 } 1305 1306 public String translateNamespacePrefixToUri(String prefix) 1307 { 1308 if(prefix.length() == 0) 1310 { 1311 return prefix; 1312 } 1313 synchronized(namespaces) 1314 { 1315 Namespace ns = (Namespace)namespaces.get(prefix); 1316 return ns == null ? null : ns.getURI(); 1317 } 1318 } 1319 } 1320 } 1321} 1322 | Popular Tags |