abstractsaxeventgenerator.java
来自「jsr170接口的java实现。是个apache的开源项目。」· Java 代码 · 共 450 行
JAVA
450 行
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.jackrabbit.core.xml;import java.util.HashMap;import java.util.Map;import org.apache.jackrabbit.name.NameException;import org.apache.jackrabbit.name.QName;import org.apache.jackrabbit.name.SessionNamespaceResolver;import org.apache.jackrabbit.name.NamespaceResolver;import org.apache.jackrabbit.name.NameFormat;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.xml.sax.ContentHandler;import org.xml.sax.SAXException;import org.xml.sax.helpers.AttributesImpl;import javax.jcr.Node;import javax.jcr.NodeIterator;import javax.jcr.Property;import javax.jcr.PropertyIterator;import javax.jcr.RepositoryException;import javax.jcr.Session;/** * <code>AbstractSAXEventGenerator</code> serves as the base class for * <code>SysViewSAXEventGenerator</code> and <code>DocViewSAXEventGenerator</code> * <p/> * It traverses a tree of <code>Node</code> & <code>Property</code> * instances, and calls the abstract methods * <ul> * <li><code>{@link #entering(Node, int)}</code></li> * <li><code>{@link #enteringProperties(Node, int)}</code></li> * <li><code>{@link #leavingProperties(Node, int)}</code></li> * <li><code>{@link #leaving(Node, int)}</code></li> * <li><code>{@link #entering(Property, int)}</code></li> * <li><code>{@link #leaving(Property, int)}</code></li> * </ul> * for every item it encounters. */abstract class AbstractSAXEventGenerator { private static Logger log = LoggerFactory.getLogger(AbstractSAXEventGenerator.class); /** * the session to be used for resolving namespace mappings */ protected final Session session; /** * the session's namespace resolver */ protected final NamespaceResolver nsResolver; /** * the content handler to feed the SAX events to */ protected final ContentHandler contentHandler; protected final Node startNode; protected final boolean skipBinary; protected final boolean noRecurse; /** * the set of namespace declarations that have already been serialized */ protected NamespaceStack namespaces; /** * The jcr:primaryType property name (allowed for session-local prefix mappings) */ protected final String jcrPrimaryType; /** * The jcr:mixinTypes property name (allowed for session-local prefix mappings) */ protected final String jcrMixinTypes; /** * The jcr:uuid property name (allowed for session-local prefix mappings) */ protected final String jcrUUID; /** * The jcr:root node name (allowed for session-local prefix mappings) */ protected final String jcrRoot; /** * The jcr:xmltext node name (allowed for session-local prefix mappings) */ protected final String jcrXMLText; /** * The jcr:xmlCharacters property name (allowed for session-local prefix mappings) */ protected final String jcrXMLCharacters; /** * Constructor * * @param node the node state which should be serialized * @param noRecurse if true, only <code>node</code> and its properties will * be serialized; otherwise the entire hierarchy starting with * <code>node</code> will be serialized. * @param skipBinary flag governing whether binary properties are to be serialized. * @param contentHandler the content handler to feed the SAX events to * @throws RepositoryException if an error occurs */ protected AbstractSAXEventGenerator(Node node, boolean noRecurse, boolean skipBinary, ContentHandler contentHandler) throws RepositoryException { startNode = node; session = node.getSession(); nsResolver = new SessionNamespaceResolver(session); this.contentHandler = contentHandler; this.skipBinary = skipBinary; this.noRecurse = noRecurse; // start with an empty set of known prefixes this.namespaces = new NamespaceStack(null); // resolve the names of some wellknown properties // allowing for session-local prefix mappings try { jcrPrimaryType = NameFormat.format(QName.JCR_PRIMARYTYPE, nsResolver); jcrMixinTypes = NameFormat.format(QName.JCR_MIXINTYPES, nsResolver); jcrUUID = NameFormat.format(QName.JCR_UUID, nsResolver); jcrRoot = NameFormat.format(QName.JCR_ROOT, nsResolver); jcrXMLText = NameFormat.format(QName.JCR_XMLTEXT, nsResolver); jcrXMLCharacters = NameFormat.format(QName.JCR_XMLCHARACTERS, nsResolver); } catch (NameException e) { // should never get here... String msg = "internal error: failed to resolve namespace mappings"; log.error(msg, e); throw new RepositoryException(msg, e); } } /** * Serializes the hierarchy of nodes and properties. * * @throws RepositoryException if an error occurs while traversing the hierarchy * @throws SAXException if an error occured while feeding the events * to the content handler */ public void serialize() throws RepositoryException, SAXException { // start document and declare namespaces contentHandler.startDocument(); startNamespaceDeclarations(); // serialize node and subtree process(startNode, 0); // clear namespace declarations and end document endNamespaceDeclarations(); contentHandler.endDocument(); } /** * @throws RepositoryException * @throws SAXException */ protected void startNamespaceDeclarations() throws RepositoryException, SAXException { // start namespace declarations String[] prefixes = session.getNamespacePrefixes(); for (int i = 0; i < prefixes.length; i++) { String prefix = prefixes[i]; if (QName.NS_XML_PREFIX.equals(prefix)) { // skip 'xml' prefix as this would be an illegal namespace declaration continue; } String uri = session.getNamespaceURI(prefix); contentHandler.startPrefixMapping(prefix, uri); } } /** * @throws RepositoryException * @throws SAXException */ protected void endNamespaceDeclarations() throws RepositoryException, SAXException { // end namespace declarations String[] prefixes = session.getNamespacePrefixes(); for (int i = 0; i < prefixes.length; i++) { String prefix = prefixes[i]; if (QName.NS_XML_PREFIX.equals(prefix)) { // skip 'xml' prefix as this would be an illegal namespace declaration continue; } contentHandler.endPrefixMapping(prefix); } } /** * Adds explicit <code>xmlns:prefix="uri"</code> attributes to the * XML element as required (e.g., normally just on the root * element). The effect is the same as setting the * "<code>http://xml.org/sax/features/namespace-prefixes</code>" * property on an SAX parser. * * @param level level of the current XML element * @param attributes attributes of the current XML element * @throws RepositoryException on a repository error */ protected void addNamespacePrefixes(int level, AttributesImpl attributes) throws RepositoryException { String[] prefixes = session.getNamespacePrefixes(); NamespaceStack newNamespaces = null; for (int i = 0; i < prefixes.length; i++) { String prefix = prefixes[i]; if (prefix.length() > 0 && !QName.NS_XML_PREFIX.equals(prefix)) { String uri = session.getNamespaceURI(prefix); // get the matching namespace from previous declarations String mappedToNs = this.namespaces.getNamespaceURI(prefix); if (!uri.equals(mappedToNs)) { // when not the same, add a declaration attributes.addAttribute( QName.NS_XMLNS_URI, prefix, QName.NS_XMLNS_PREFIX + ":" + prefix, "CDATA", uri); if (newNamespaces == null) { // replace current namespace stack when needed newNamespaces = new NamespaceStack(this.namespaces); this.namespaces = newNamespaces; } // remember the new declaration newNamespaces.setNamespacePrefix(prefix, uri); } } } } /** * @param node * @param level * @throws RepositoryException * @throws SAXException */ protected void process(Node node, int level) throws RepositoryException, SAXException { // enter node entering(node, level); // enter properties enteringProperties(node, level); // serialize jcr:primaryType, jcr:mixinTypes & jcr:uuid first: // jcr:primaryType if (node.hasProperty(jcrPrimaryType)) { process(node.getProperty(jcrPrimaryType), level + 1); } else { String msg = "internal error: missing jcr:primaryType property on node " + node.getPath(); log.debug(msg); throw new RepositoryException(msg); } // jcr:mixinTypes if (node.hasProperty(jcrMixinTypes)) { process(node.getProperty(jcrMixinTypes), level + 1); } // jcr:uuid if (node.hasProperty(jcrUUID)) { process(node.getProperty(jcrUUID), level + 1); } // serialize remaining properties PropertyIterator propIter = node.getProperties(); while (propIter.hasNext()) { Property prop = propIter.nextProperty(); String name = prop.getName(); if (jcrPrimaryType.equals(name) || jcrMixinTypes.equals(name) || jcrUUID.equals(name)) { continue; } // serialize property process(prop, level + 1); } // leaving properties leavingProperties(node, level); if (!noRecurse) { // child nodes NodeIterator nodeIter = node.getNodes(); while (nodeIter.hasNext()) { // recurse Node childNode = nodeIter.nextNode(); // remember the current namespace declarations NamespaceStack previousNamespaces = this.namespaces; process(childNode, level + 1); // restore the effective namespace declarations // (from before visiting the child node) this.namespaces = previousNamespaces; } } // leaving node leaving(node, level); } /** * @param prop * @param level * @throws RepositoryException * @throws SAXException */ protected void process(Property prop, int level) throws RepositoryException, SAXException { // serialize property entering(prop, level); leaving(prop, level); } /** * @param node * @param level * @throws RepositoryException * @throws SAXException */ protected abstract void entering(Node node, int level) throws RepositoryException, SAXException; /** * @param node * @param level * @throws RepositoryException * @throws SAXException */ protected abstract void enteringProperties(Node node, int level) throws RepositoryException, SAXException; /** * @param node * @param level * @throws RepositoryException * @throws SAXException */ protected abstract void leavingProperties(Node node, int level) throws RepositoryException, SAXException; /** * @param node * @param level * @throws RepositoryException * @throws SAXException */ protected abstract void leaving(Node node, int level) throws RepositoryException, SAXException; /** * @param prop * @param level * @throws RepositoryException * @throws SAXException */ protected abstract void entering(Property prop, int level) throws RepositoryException, SAXException; /** * @param prop * @param level * @throws RepositoryException * @throws SAXException */ protected abstract void leaving(Property prop, int level) throws RepositoryException, SAXException; /** * Implements a simple stack of namespace declarations. */ private static class NamespaceStack { /** * Parent stack (may be <code>null</code>) */ private final NamespaceStack parent; /** * Local namespace declarations. */ private final Map namespaces; /** * Instantiate a new stack * * @param parent parent stack (may be <code>null</code> for the initial stack) */ public NamespaceStack(NamespaceStack parent) { this.parent = parent; this.namespaces = new HashMap(); } /** * Obtain namespace URI for a prefix * * @param prefix prefix * @return namespace URI (or <code>null</code> when unknown) */ public String getNamespaceURI(String prefix) { String namespace = (String) namespaces.get(prefix); if (namespace != null) { // found in this element, return right away return namespace; } else if (parent != null) { // ask parent, when present return parent.getNamespaceURI(prefix); } else { return null; } } /** * Add a new prefix mapping * * @param prefix namespace prefix * @param uri namespace URI */ public void setNamespacePrefix(String prefix, String uri) { namespaces.put(prefix, uri); } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?