栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

FreeMarker代码分析第四篇

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

FreeMarker代码分析第四篇

2021SC@SDUSC

FreeMarker代码分析第四篇
  • jdom包
    • NodeListModel.java
      • 代码展示
      • 代码分析
        • NodeListModel()构造方法
        • createNodeListModel()方法
        • isEmpty()方法
        • getAsString()方法

jdom包 NodeListModel.java 代码展示

package freemarker.ext.jdom;

import java.io.FileReader;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.linkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import org.jaxen.Context;
import org.jaxen.JaxenException;
import org.jaxen.NamespaceContext;
import org.jaxen.jdom.JDOMXPath;
import org.jdom.Attribute;
import org.jdom.CDATA;
import org.jdom.Comment;
import org.jdom.DocType;
import org.jdom.document;
import org.jdom.Element;
import org.jdom.EntityRef;
import org.jdom.Namespace;
import org.jdom.ProcessingInstruction;
import org.jdom.Text;
import org.jdom.output.XMLOutputter;

import freemarker.template.SimpleHash;
import freemarker.template.SimpleScalar;
import freemarker.template.Template;
import freemarker.template.TemplateCollectionModel;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateMethodModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateModelIterator;
import freemarker.template.TemplateScalarModel;
import freemarker.template.TemplateSequenceModel;
import freemarker.template._TemplateAPI;


@Deprecated
public class NodeListModel
implements
    TemplateHashModel,
    TemplateMethodModel,
    TemplateCollectionModel,
    TemplateSequenceModel,
    TemplateScalarModel {
    private static final AttributeXMLOutputter OUTPUT = new AttributeXMLOutputter();
    // A convenience singleton for representing a node list without nodes.
    private static final NodeListModel EMPTY = new NodeListModel(null, false);

    // Cache of already parsed XPath expressions
    private static final Map XPATH_CACHE = new WeakHashMap();

    private static final NamedNodeOperator NAMED_CHILDREN_OP = new NamedChildrenOp();
    private static final NamedNodeOperator NAMED_ATTRIBUTE_OP = new NamedAttributeOp();
    private static final NodeOperator ALL_ATTRIBUTES_OP = new AllAttributesOp();
    private static final NodeOperator ALL_CHILDREN_OP = new AllChildrenOp();
    private static final Map OPERATIONS = createOperations();
    private static final Map SPECIAL_OPERATIONS = createSpecialOperations();
    private static final int SPECIAL_OPERATION_COPY = 0;
    private static final int SPECIAL_OPERATION_UNIQUE = 1;
    private static final int SPECIAL_OPERATION_FILTER_NAME = 2;
    private static final int SPECIAL_OPERATION_FILTER_TYPE = 3;
    private static final int SPECIAL_OPERATION_QUERY_TYPE = 4;
    private static final int SPECIAL_OPERATION_REGISTER_NAMESPACE = 5;
    private static final int SPECIAL_OPERATION_PLAINTEXT = 6;

    // The contained nodes
    private final List nodes;
    private final Map namespaces;

    
    public NodeListModel(document document) {
        nodes = document == null ? Collections.EMPTY_LIST : Collections.singletonList(document);
        namespaces = new HashMap();
    }

    
    public NodeListModel(Element element) {
        nodes = element == null ? Collections.EMPTY_LIST : Collections.singletonList(element);
        namespaces = new HashMap();
    }

    private NodeListModel(Object object, Map namespaces) {
        nodes = object == null ? Collections.EMPTY_LIST : Collections.singletonList(object);
        this.namespaces = namespaces;
    }

    
    public NodeListModel(List nodes) {
        this(nodes, true);
    }

    
    public NodeListModel(List nodes, boolean copy) {
        this.nodes = copy && nodes != null ? new ArrayList(nodes) : (nodes == null ? Collections.EMPTY_LIST : nodes);
        namespaces = new HashMap();
    }

    private NodeListModel(List nodes, Map namespaces) {
        this.nodes = nodes == null ? Collections.EMPTY_LIST : nodes;
        this.namespaces = namespaces;
    }

    private static final NodeListModel createNodeListModel(List list, Map namespaces) {
        if (list == null || list.isEmpty()) {
            if (namespaces.isEmpty()) {
                return EMPTY;
            } else {
                return new NodeListModel(Collections.EMPTY_LIST, namespaces);
            }
        }
        if (list.size() == 1) return new NodeListModel(list.get(0), namespaces);
        return new NodeListModel(list, namespaces);
    }

    
    @Override
    public boolean isEmpty() {
        return nodes.isEmpty();
    }

    
    @Override
    public String getAsString()
    throws TemplateModelException {
        if (isEmpty())
            return "";

        java.io.StringWriter sw = new java.io.StringWriter(nodes.size() * 128);
        try {
            for (Iterator i = nodes.iterator(); i.hasNext(); ) {
                Object node = i.next();
                if (node instanceof Element)
                    OUTPUT.output((Element) node, sw);
                else if (node instanceof Attribute)
                    OUTPUT.output((Attribute) node, sw);
                else if (node instanceof String)
                    sw.write(OUTPUT.escapeElementEntities(node.toString()));
                else if (node instanceof Text)
                    OUTPUT.output((Text) node, sw);
                else if (node instanceof document)
                    OUTPUT.output((document) node, sw);
                else if (node instanceof ProcessingInstruction)
                    OUTPUT.output((ProcessingInstruction) node, sw);
                else if (node instanceof Comment)
                    OUTPUT.output((Comment) node, sw);
                else if (node instanceof CDATA)
                    OUTPUT.output((CDATA) node, sw);
                else if (node instanceof DocType)
                    OUTPUT.output((DocType) node, sw);
                else if (node instanceof EntityRef)
                    OUTPUT.output((EntityRef) node, sw);
                else
                    throw new TemplateModelException(node.getClass().getName() + " is not a core JDOM class");
            }
        } catch (IOException e) {
            throw new TemplateModelException(e.getMessage());
        }
        return sw.toString();
    }


    
    @Override
    public TemplateModel get(String key)
    throws TemplateModelException {
        if (isEmpty())
            return EMPTY;

        if (key == null || key.length() == 0)
            throw new TemplateModelException("Invalid key [" + key + "]");

        NodeOperator op = null;
        NamedNodeOperator nop = null;
        String name = null;

        switch (key.charAt(0)) {
            case '@':
                {
                    if (key.length() != 2 || key.charAt(1) != '*') {
                        // Generic attribute key
                        nop = NAMED_ATTRIBUTE_OP;
                        name = key.substring(1);
                    } else
                        // It is @*
                        op = ALL_ATTRIBUTES_OP;

                    break;
                }
            case '*':
                {
                    if (key.length() == 1)
                        op = ALL_CHILDREN_OP;
                    else
                        // Explicitly disallow any other identifier starting with asterisk
                        throw new TemplateModelException("Invalid key [" + key + "]");

                    break;
                }
            case 'x':
            case '_':
                {
                    op = (NodeOperator) OPERATIONS.get(key);
                    if (op == null) {
                        // Some special operation?
                        Integer specop = (Integer) SPECIAL_OPERATIONS.get(key);
                        if (specop != null) {
                            switch (specop.intValue()) {
                                case SPECIAL_OPERATION_COPY:
                                {
                                    synchronized (namespaces) {
                                        return new NodeListModel(nodes, (Map) ((HashMap) namespaces).clone());
                                    }
                                }
                                case SPECIAL_OPERATION_UNIQUE:
                                    return new NodeListModel(removeDuplicates(nodes), namespaces);
                                case SPECIAL_OPERATION_FILTER_NAME:
                                    return new NameFilter();
                                case SPECIAL_OPERATION_FILTER_TYPE:
                                    return new TypeFilter();
                                case SPECIAL_OPERATION_QUERY_TYPE:
                                    return getType();
                                case SPECIAL_OPERATION_REGISTER_NAMESPACE:
                                    return new RegisterNamespace();
                                case SPECIAL_OPERATION_PLAINTEXT:
                                    return getPlainText();
                            }
                        }
                    }
                    break;
                }
        }

        if (op == null && nop == null) {
            nop = NAMED_CHILDREN_OP;
            name = key;
        }

        List list = null;
        if (op != null)
            list = evaluateElementOperation(op, nodes);
        else {
            String localName = name;
            Namespace namespace = Namespace.NO_NAMESPACE;
            int colon = name.indexOf(':');
            if (colon != -1) {
                localName = name.substring(colon + 1);
                String nsPrefix = name.substring(0, colon);
                synchronized (namespaces) {
                    namespace = (Namespace) namespaces.get(nsPrefix);
                }
                if (namespace == null) {
                    if (nsPrefix.equals("xml"))
                        namespace = Namespace.XML_NAMESPACE;
                    else
                        throw new TemplateModelException("Unregistered namespace prefix '" + nsPrefix + "'");
                }
            }

            list = evaluateNamedElementOperation(nop, localName, namespace, nodes);
        }
        return createNodeListModel(list, namespaces);
    }

    private TemplateModel getType() {
        if (nodes.size() == 0)
            return new SimpleScalar("");
        Object firstNode = nodes.get(0);
        char code;
        if (firstNode instanceof Element)
            code = 'e';
        else if (firstNode instanceof Text || firstNode instanceof String)
            code = 'x';
        else if (firstNode instanceof Attribute)
            code = 'a';
        else if (firstNode instanceof EntityRef)
            code = 'n';
        else if (firstNode instanceof document)
            code = 'd';
        else if (firstNode instanceof DocType)
            code = 't';
        else if (firstNode instanceof Comment)
            code = 'c';
        else if (firstNode instanceof ProcessingInstruction)
            code = 'p';
        else
            code = '?';
        return new SimpleScalar(new String(new char[] { code}));
    }

    private SimpleScalar getPlainText()
    throws TemplateModelException {
        List list = evaluateElementOperation((TextOp) OPERATIONS.get("_text"), nodes);
        StringBuilder buf = new StringBuilder();
        for (Iterator it = list.iterator(); it.hasNext(); ) {
            buf.append(it.next());
        }
        return new SimpleScalar(buf.toString());
    }

    @Override
    public TemplateModelIterator iterator() {
        return new TemplateModelIterator()
        {
            private final Iterator it = nodes.iterator();

            @Override
            public TemplateModel next() {
                return it.hasNext() ? new NodeListModel(it.next(), namespaces) : null;
            }

            @Override
            public boolean hasNext() {
                return it.hasNext();
            }
        };
    }

    
    @Override
    public TemplateModel get(int i)
    throws TemplateModelException {
        try {
            return new NodeListModel(nodes.get(i), namespaces);
        } catch (IndexOutOfBoundsException e) {
            throw new TemplateModelException("Index out of bounds: " + e.getMessage());
        }
    }
    
    @Override
    public int size() {
        return nodes.size();
    }

    
    @Override
    public Object exec(List arguments)
    throws TemplateModelException {
        if (arguments == null || arguments.size() != 1)
            throw new TemplateModelException("Exactly one argument required for execute() on NodeTemplate");

        String xpathString = (String) arguments.get(0);
        JDOMXPathEx xpath = null;
        try {
            synchronized (XPATH_CACHE) {
                xpath = (JDOMXPathEx) XPATH_CACHE.get(xpathString);
                if (xpath == null) {
                    xpath = new JDOMXPathEx(xpathString);
                    XPATH_CACHE.put(xpathString, xpath);
                }
            }
            return createNodeListModel(xpath.selectNodes(nodes, namespaces), namespaces);
        } catch (Exception e) {
            throw new TemplateModelException("Could not evaulate XPath expression " + xpathString, e);
        }
    }

    
    public void registerNamespace(String prefix, String uri) {
        synchronized (namespaces) {
            namespaces.put(prefix, Namespace.getNamespace(prefix, uri));
        }
    }

    private interface NodeOperator {
        List operate(Object node)
        throws TemplateModelException;
    }

    private interface NamedNodeOperator {
        List operate(Object node, String localName, Namespace namespace)
        throws TemplateModelException;
    }

    private static final class AllChildrenOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            if (node instanceof Element)
                return((Element) node).getChildren();
            else if (node instanceof document) {
                Element root = ((document) node).getRootElement();
                return root == null ? Collections.EMPTY_LIST : Collections.singletonList(root);
            } 
 // With 2.1 semantics it  makes more sense to just return a null and let the core 
 // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            return null;
                
        }
    }

    private static final class NamedChildrenOp implements NamedNodeOperator {
        @Override
        public List operate(Object node, String localName, Namespace namespace) {
            if (node instanceof Element) {
                return((Element) node).getChildren(localName, namespace);
            } else if (node instanceof document) {
                Element root = ((document) node).getRootElement();
                if (root != null &&
                    root.getName().equals(localName) &&
                    root.getNamespaceURI().equals(namespace.getURI())) {
                    return Collections.singletonList(root);
                } else
                    return Collections.EMPTY_LIST;
            } 
 // With 2.1 semantics it  makes more sense to just return a null and let the core 
 // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            return null;
                 
        }
    }

    private static final class AllAttributesOp implements NodeOperator {
        @Override
        public List operate(Object node) {
 // With 2.1 semantics it  makes more sense to just return a null and let the core 
 // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            if (!(node instanceof Element)) {
                return null;
            }
            return ((Element) node).getAttributes();
                
        }
    }

    private static final class NamedAttributeOp implements NamedNodeOperator {
        @Override
        public List operate(Object node, String localName, Namespace namespace) {
            Attribute attr = null;
            if (node instanceof Element) {
                Element element = (Element) node;
                attr = element.getAttribute(localName, namespace);
            } else if (node instanceof ProcessingInstruction) {
                ProcessingInstruction pi = (ProcessingInstruction) node;
                if ("target".equals(localName))
                    attr = new Attribute("target", pi.getTarget());
                else if ("data".equals(localName))
                    attr = new Attribute("data", pi.getData());
                else
                    attr = new Attribute(localName, pi.getValue(localName));
            } else if (node instanceof DocType) {
                DocType doctype = (DocType) node;
                if ("publicId".equals(localName))
                    attr = new Attribute("publicId", doctype.getPublicID());
                else if ("systemId".equals(localName))
                    attr = new Attribute("systemId", doctype.getSystemID());
                else if ("elementName".equals(localName))
                    attr = new Attribute("elementName", doctype.getElementName());
            } 
            // With 2.1 semantics it  makes more sense to just return a null and let the core 
            // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            else {
                return null;
            }

            return attr == null ? Collections.EMPTY_LIST : Collections.singletonList(attr);
        }
    }

    private static final class NameOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            if (node instanceof Element)
                return Collections.singletonList(((Element) node).getName());
            else if (node instanceof Attribute)
                return Collections.singletonList(((Attribute) node).getName());
            else if (node instanceof EntityRef)
                return Collections.singletonList(((EntityRef) node).getName());
            else if (node instanceof ProcessingInstruction)
                return Collections.singletonList(((ProcessingInstruction) node).getTarget());
            else if (node instanceof DocType)
                return Collections.singletonList(((DocType) node).getPublicID());
            else
                return null;
            // With 2.1 semantics it  makes more sense to just return a null and let the core 
            // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
//                throw new TemplateModelException("_name can not be applied on " + node.getClass());
        }
    }

    private static final class QNameOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            if (node instanceof Element)
                return Collections.singletonList(((Element) node).getQualifiedName());
            else if (node instanceof Attribute)
                return Collections.singletonList(((Attribute) node).getQualifiedName());
            // With 2.1 semantics it  makes more sense to just return a null and let the core 
            // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            return null;
//            throw new TemplateModelException("_qname can not be applied on " + node.getClass());
        }
    }

    private static final class NamespaceUriOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            if (node instanceof Element)
                return Collections.singletonList(((Element) node).getNamespace().getURI());
            else if (node instanceof Attribute)
                return Collections.singletonList(((Attribute) node).getNamespace().getURI());
            // With 2.1 semantics it  makes more sense to just return a null and let the core 
            // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            return null;
//            throw new TemplateModelException("_nsuri can not be applied on " + node.getClass());
        }
    }

    private static final class NamespacePrefixOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            if (node instanceof Element)
                return Collections.singletonList(((Element) node).getNamespace().getPrefix());
            else if (node instanceof Attribute)
                return Collections.singletonList(((Attribute) node).getNamespace().getPrefix());
            // With 2.1 semantics it  makes more sense to just return a null and let the core 
            // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            return null;
//            throw new TemplateModelException("_nsprefix can not be applied on " + node.getClass());
        }
    }

    private static final class CanonicalNameOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            if (node instanceof Element) {
                Element element = (Element) node;
                return Collections.singletonList(element.getNamespace().getURI() + element.getName());
            } else if (node instanceof Attribute) {
                Attribute attribute = (Attribute) node;
                return Collections.singletonList(attribute.getNamespace().getURI() + attribute.getName());
            }
            // With 2.1 semantics it  makes more sense to just return a null and let the core 
            // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            return null;
//            throw new TemplateModelException("_cname can not be applied on " + node.getClass());
        }
    }


    private static final Element getParent(Object node) {
        if (node instanceof Element)
            return((Element) node).getParent();
        else if (node instanceof Attribute)
            return((Attribute) node).getParent();
        else if (node instanceof Text)
            return((Text) node).getParent();
        else if (node instanceof ProcessingInstruction)
            return((ProcessingInstruction) node).getParent();
        else if (node instanceof Comment)
            return((Comment) node).getParent();
        else if (node instanceof EntityRef)
            return((EntityRef) node).getParent();
        else
            // With 2.1 semantics it  makes more sense to just return a null and let the core 
            // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            return null;
//            throw new TemplateModelException("_parent can not be applied on " + node.getClass());
    }

    private static final class ParentOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            Element parent = getParent(node);
            return parent == null ? Collections.EMPTY_LIST : Collections.singletonList(parent);
        }
    }

    private static final class AncestorOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            Element parent = getParent(node);
            if (parent == null) return Collections.EMPTY_LIST;
            linkedList list = new linkedList();
            do {
                list.addFirst(parent);
                parent = parent.getParent();
            } while (parent != null);
            return list;
        }
    }

    private static final class AncestorOrSelfOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            Element parent = getParent(node);
            if (parent == null) return Collections.singletonList(node);
            linkedList list = new linkedList();
            list.addFirst(node);
            do {
                list.addFirst(parent);
                parent = parent.getParent();
            } while (parent != null);
            return list;
        }
    }

    private static class DescendantOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            linkedList list = new linkedList();
            if (node instanceof Element) {
                addChildren((Element) node, list);
            } else if (node instanceof document) {
                Element root = ((document) node).getRootElement();
                list.add(root);
                addChildren(root, list);
            } else
                // With 2.1 semantics it  makes more sense to just return a null and let the core 
                // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
                return null;
//                throw new TemplateModelException("_descendant can not be applied on " + node.getClass());

            return list;
        }

        private void addChildren(Element element, List list) {
            List children = element.getChildren();
            Iterator it = children.iterator();
            while (it.hasNext()) {
                Element child = (Element) it.next();
                list.add(child);
                addChildren(child, list);
            }
        }
    }

    private static final class DescendantOrSelfOp extends DescendantOp {
        @Override
        public List operate(Object node) {
            linkedList list = (linkedList) super.operate(node);
            list.addFirst(node);
            return list;
        }
    }

    private static final class documentOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            document doc = null;
            if (node instanceof Element)
                doc = ((Element) node).getdocument();
            else if (node instanceof Attribute) {
                Element parent = ((Attribute) node).getParent();
                doc = parent == null ? null : parent.getdocument();
            } else if (node instanceof Text) {
                Element parent = ((Text) node).getParent();
                doc = parent == null ? null : parent.getdocument();
            } else if (node instanceof document)
                doc = (document) node;
            else if (node instanceof ProcessingInstruction)
                doc = ((ProcessingInstruction) node).getdocument();
            else if (node instanceof EntityRef)
                doc = ((EntityRef) node).getdocument();
            else if (node instanceof Comment)
                doc = ((Comment) node).getdocument();
            else
                // With 2.1 semantics it  makes more sense to just return a null and let the core 
                // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
                return null;
//                throw new TemplateModelException("_document can not be applied on " + node.getClass());

            return doc == null ? Collections.EMPTY_LIST : Collections.singletonList(doc);
        }
    }

    private static final class DocTypeOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            if (node instanceof document) {
                DocType doctype = ((document) node).getDocType();
                return doctype == null ? Collections.EMPTY_LIST : Collections.singletonList(doctype);
            } else
                // With 2.1 semantics it  makes more sense to just return a null and let the core 
                // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
                return null;
//                throw new TemplateModelException("_doctype can not be applied on " + node.getClass());
        }
    }

    private static final class ContentOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            if (node instanceof Element)
                return((Element) node).getContent();
            else if (node instanceof document)
                return((document) node).getContent();
            // With 2.1 semantics it  makes more sense to just return a null and let the core 
            // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            return null;
//            throw new TemplateModelException("_content can not be applied on " + node.getClass());
        }
    }

    private static final class TextOp implements NodeOperator {
        @Override
        public List operate(Object node) {
            if (node instanceof Element)
                return Collections.singletonList(((Element) node).getTextTrim());
            if (node instanceof Attribute)
                return Collections.singletonList(((Attribute) node).getValue());
            if (node instanceof CDATA)
                return Collections.singletonList(((CDATA) node).getText());
            if (node instanceof Comment)
                return Collections.singletonList(((Comment) node).getText());
            if (node instanceof ProcessingInstruction)
                return Collections.singletonList(((ProcessingInstruction) node).getData());
            // With 2.1 semantics it  makes more sense to just return a null and let the core 
            // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR)
            return null;
//            throw new TemplateModelException("_text can not be applied on " + node.getClass());
        }
    }

    private static final List evaluateElementOperation(NodeOperator op, List nodes)
    throws TemplateModelException {
        int s = nodes.size();
        List[] lists = new List[s];
        int l = 0;
        {
            int i = 0;
            Iterator it = nodes.iterator();
            while (it.hasNext()) {
                List list = op.operate(it.next());
                if (list != null) {
                    lists[i++] = list;
                    l += list.size();
                }
            }
        }
        List retval = new ArrayList(l);
        for (int i = 0; i < s; ++i) {
            if (lists[i] != null) {
                retval.addAll(lists[i]);
            }
        }
        return retval;
    }

    private static final List evaluateNamedElementOperation(NamedNodeOperator op, String localName, Namespace namespace, List nodes)
    throws TemplateModelException {
        int s = nodes.size();
        List[] lists = new List[s];
        int l = 0;
        {
            int i = 0;
            Iterator it = nodes.iterator();
            while (it.hasNext()) {
                List list = op.operate(it.next(), localName, namespace);
                lists[i++] = list;
                l += list.size();
            }
        }
        List retval = new ArrayList(l);
        for (int i = 0; i < s; ++i)
            retval.addAll(lists[i]);
        return retval;
    }

    private static final List removeDuplicates(List list) {
        int s = list.size();
        ArrayList ulist = new ArrayList(s);
        Set set = new HashSet(s * 4 / 3, .75f);
        Iterator it = list.iterator();
        while (it.hasNext()) {
            Object o = it.next();
            if (set.add(o))
                ulist.add(o);
        }
        ulist.trimToSize();
        return ulist;
    }

    private static final Map createOperations() {
        Map map = new HashMap();

        map.put("_ancestor", new AncestorOp());
        map.put("_ancestorOrSelf", new AncestorOrSelfOp());
        map.put("_attributes", ALL_ATTRIBUTES_OP);
        map.put("_children", ALL_CHILDREN_OP);
        map.put("_cname", new CanonicalNameOp());
        map.put("_content", new ContentOp());
        map.put("_descendant", new DescendantOp());
        map.put("_descendantOrSelf", new DescendantOrSelfOp());
        map.put("_document", new documentOp());
        map.put("_doctype", new DocTypeOp());
        map.put("_name", new NameOp());
        map.put("_nsprefix", new NamespacePrefixOp());
        map.put("_nsuri", new NamespaceUriOp());
        map.put("_parent", new ParentOp());
        map.put("_qname", new QNameOp());
        map.put("_text", new TextOp());

        return map;
    }

    private static final Map createSpecialOperations() {
        Map map = new HashMap();

        Integer copy = Integer.valueOf(SPECIAL_OPERATION_COPY);
        Integer unique = Integer.valueOf(SPECIAL_OPERATION_UNIQUE);
        Integer fname = Integer.valueOf(SPECIAL_OPERATION_FILTER_NAME);
        Integer ftype = Integer.valueOf(SPECIAL_OPERATION_FILTER_TYPE);
        Integer type = Integer.valueOf(SPECIAL_OPERATION_QUERY_TYPE);
        Integer regns = Integer.valueOf(SPECIAL_OPERATION_REGISTER_NAMESPACE);
        Integer plaintext = Integer.valueOf(SPECIAL_OPERATION_PLAINTEXT);

        map.put("_copy", copy);
        map.put("_unique", unique);
        map.put("_fname", fname);
        map.put("_ftype", ftype);
        map.put("_type", type);
        map.put("_registerNamespace", regns);
        map.put("_plaintext", plaintext);

        // These are in for backward compatibility
        map.put("x_copy", copy);
        map.put("x_unique", unique);
        map.put("x_fname", fname);
        map.put("x_ftype", ftype);
        map.put("x_type", type);

        return map;
    }

    private final class RegisterNamespace implements TemplateMethodModel {
        public boolean isEmpty() {
            return false;
        }

        @Override
        public Object exec(List arguments)
        throws TemplateModelException {
            if (arguments.size() != 2)
                throw new TemplateModelException("_registerNamespace(prefix, uri) requires two arguments");

            registerNamespace((String) arguments.get(0), (String) arguments.get(1));

            return TemplateScalarModel.EMPTY_STRING;
        }
    }

    private final class NameFilter implements TemplateMethodModel {
        public boolean isEmpty() {
            return false;
        }

        @Override
        public Object exec(List arguments) {
            Set names = new HashSet(arguments);
            List list = new linkedList(nodes);
            Iterator it = list.iterator();
            while (it.hasNext()) {
                Object node = it.next();
                String name = null;
                if (node instanceof Element)
                    name = ((Element) node).getName();
                else if (node instanceof Attribute)
                    name = ((Attribute) node).getName();
                else if (node instanceof ProcessingInstruction)
                    name = ((ProcessingInstruction) node).getTarget();
                else if (node instanceof EntityRef)
                    name = ((EntityRef) node).getName();
                else if (node instanceof DocType)
                    name = ((DocType) node).getPublicID();

                if (name == null || !names.contains(name))
                    it.remove();
            }
            return createNodeListModel(list, namespaces);
        }
    }

    private final class TypeFilter implements TemplateMethodModel {
        public boolean isEmpty() {
            return false;
        }

        @Override
        public Object exec(List arguments)
        throws TemplateModelException {
            if (arguments == null || arguments.size() == 0)
                throw new TemplateModelException("_type expects exactly one argument");
            String arg = (String) arguments.get(0);
            boolean invert = arg.indexOf('!') != -1;
            // NOTE: true in each of these variables means 'remove', not 'keep'
            // This is so we don't invert their values in the loop. So,
            // a is true <--> (a is not present in the string) xor invert.
            boolean a = invert != (arg.indexOf('a') == -1);
            boolean c = invert != (arg.indexOf('c') == -1);
            boolean d = invert != (arg.indexOf('d') == -1);
            boolean e = invert != (arg.indexOf('e') == -1);
            boolean n = invert != (arg.indexOf('n') == -1);
            boolean p = invert != (arg.indexOf('p') == -1);
            boolean t = invert != (arg.indexOf('t') == -1);
            boolean x = invert != (arg.indexOf('x') == -1);

            linkedList list = new linkedList(nodes);
            Iterator it = list.iterator();
            while (it.hasNext()) {
                Object node = it.next();
                if ((node instanceof Element && e)
                    || (node instanceof Attribute && a)
                    || (node instanceof String && x)
                    || (node instanceof Text && x)
                    || (node instanceof ProcessingInstruction && p)
                    || (node instanceof Comment && c)
                    || (node instanceof EntityRef && n)
                    || (node instanceof document && d)
                    || (node instanceof DocType && t))
                    it.remove();
            }
            return createNodeListModel(list, namespaces);
        }
    }

    
    @Deprecated
    public static void main(String[] args)
    throws Exception {
        org.jdom.input.SAXBuilder builder = new org.jdom.input.SAXBuilder();
        document document = builder.build(System.in);
        SimpleHash model = new SimpleHash(_TemplateAPI.SAFE_OBJECT_WRAPPER);
        model.put("document", new NodeListModel(document));
        FileReader fr = new FileReader(args[0]);
        Template template = new Template(args[0], fr);
        Writer w = new java.io.OutputStreamWriter(System.out);
        template.process(model, w);
        w.flush();
        w.close();
    }

    private static final class AttributeXMLOutputter extends XMLOutputter {
        public void output(Attribute attribute, Writer out)
        throws IOException {
            out.write(" ");
            out.write(attribute.getQualifiedName());
            out.write("=");

            out.write(""");
            out.write(escapeAttributeEntities(attribute.getValue()));
            out.write(""");
        }
    }

    private static final class JDOMXPathEx
    extends
        JDOMXPath {
        JDOMXPathEx(String path)
        throws JaxenException {
            super(path);
        }

        public List selectNodes(Object object, Map namespaces)
        throws JaxenException {
            Context context = getContext(object);
            context.getContextSupport().setNamespaceContext(new NamespaceContextImpl(namespaces));
            return selectNodesForContext(context);
        } 

        private static final class NamespaceContextImpl
        implements
            NamespaceContext {
            private final Map namespaces;
            
            NamespaceContextImpl(Map namespaces) {
                this.namespaces = namespaces;
            }
            
            @Override
            public String translateNamespacePrefixToUri(String prefix) {
                // Empty prefix always maps to empty URL in XPath
                if (prefix.length() == 0) {
                    return prefix;
                }
                synchronized (namespaces) {
                    Namespace ns = (Namespace) namespaces.get(prefix);
                    return ns == null ? null : ns.getURI();
                }   
            }
        }
    }
}

代码分析 NodeListModel()构造方法
	
	public NodeListModel(document document) {
        nodes = document == null ? Collections.EMPTY_LIST : Collections.singletonList(document);
        namespaces = new HashMap();
    }

    
    public NodeListModel(Element element) {
        nodes = element == null ? Collections.EMPTY_LIST : Collections.singletonList(element);
        namespaces = new HashMap();
    }
	
    private NodeListModel(Object object, Map namespaces) {
        nodes = object == null ? Collections.EMPTY_LIST : Collections.singletonList(object);
        this.namespaces = namespaces;
    }

    
    public NodeListModel(List nodes) {
        this(nodes, true);
    }

    
    public NodeListModel(List nodes, boolean copy) {
        this.nodes = copy && nodes != null ? new ArrayList(nodes) : (nodes == null ? Collections.EMPTY_LIST : nodes);
        namespaces = new HashMap();
    }
	
    private NodeListModel(List nodes, Map namespaces) {
        this.nodes = nodes == null ? Collections.EMPTY_LIST : nodes;
        this.namespaces = namespaces;
    }
createNodeListModel()方法
private static final NodeListModel createNodeListModel(List list, Map namespaces) {
        if (list == null || list.isEmpty()) {
            if (namespaces.isEmpty()) {
                return EMPTY;
            } else {
                return new NodeListModel(Collections.EMPTY_LIST, namespaces);
            }
        }
        if (list.size() == 1) return new NodeListModel(list.get(0), namespaces);
	  return new NodeListModel(list, namespaces);
    }
isEmpty()方法
	
    @Override
    public boolean isEmpty() {
        return nodes.isEmpty();
    }
getAsString()方法
	
    @Override
    public String getAsString()
    throws TemplateModelException {
        if (isEmpty())
            return "";

        java.io.StringWriter sw = new java.io.StringWriter(nodes.size() * 128);
        try {
            for (Iterator i = nodes.iterator(); i.hasNext(); ) {
                Object node = i.next();
                if (node instanceof Element)
                    OUTPUT.output((Element) node, sw);
                else if (node instanceof Attribute)
                    OUTPUT.output((Attribute) node, sw);
                else if (node instanceof String)
                    sw.write(OUTPUT.escapeElementEntities(node.toString()));
                else if (node instanceof Text)
                    OUTPUT.output((Text) node, sw);
                else if (node instanceof document)
                    OUTPUT.output((document) node, sw);
                else if (node instanceof ProcessingInstruction)
                    OUTPUT.output((ProcessingInstruction) node, sw);
                else if (node instanceof Comment)
                    OUTPUT.output((Comment) node, sw);
                else if (node instanceof CDATA)
                    OUTPUT.output((CDATA) node, sw);
                else if (node instanceof DocType)
                    OUTPUT.output((DocType) node, sw);
                else if (node instanceof EntityRef)
                    OUTPUT.output((EntityRef) node, sw);
                else
                    throw new TemplateModelException(node.getClass().getName() + " is not a core JDOM class");
            }
        } catch (IOException e) {
            throw new TemplateModelException(e.getMessage());
        }
        return sw.toString();
	}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/332475.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号