Package org.milyn.namespace

Source Code of org.milyn.namespace.NamespaceDeclarationStack

/*
* Milyn - Copyright (C) 2006 - 2011
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License (version 2.1) as published by the Free Software
* Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU Lesser General Public License for more details:
* http://www.gnu.org/licenses/lgpl.txt
*/
package org.milyn.namespace;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import javax.xml.XMLConstants;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;

/**
* This class is responsible for managing namespace declarations.
*
* @author zubairov
*/
public class NamespaceDeclarationStack {

    private final Stack<Map<String, String>> namespaceStack = new Stack<Map<String, String>>();
    private final Stack<XMLReader> readerStack = new Stack<XMLReader>();

    public NamespaceDeclarationStack() {
    }

    public NamespaceDeclarationStack(XMLReader xmlReader) {
        pushReader(xmlReader);
    }

  /**
   * Pushing a new element to the stack.
   *
     * @param qName Element QName.
     * @param namespace Element namespace.
   * @param attributes optional attributes or null, single element could declare multiple namespaces
   * @return modified attributes declaration in case additional prefix mapping should be included
   * @throws SAXException
   */
  public Attributes pushNamespaces(String qName, String namespace, Attributes attributes) throws SAXException {
        if(attributes == null || attributes.getLength() == 0) {
            if(namespace == null || XMLConstants.NULL_NS_URI.equals(namespace)) {
                namespaceStack.push(Collections.EMPTY_MAP);
                return attributes;
            }
        }

        Map<String, String> nsToURI = Collections.EMPTY_MAP;

        // Gather namespace declarations from the attributes
        if(attributes != null) {
            for(int i = 0; i < attributes.getLength() ; i++) {
                String attrNS = attributes.getURI(i);

                if (attrNS != null && attrNS.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
                    // Add prefix to the list of declared namespaces
                    if(nsToURI == Collections.EMPTY_MAP) {
                        nsToURI = new LinkedHashMap<String, String>();
                    }

                    String localName = attributes.getLocalName(i);
                    if (localName.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
                        nsToURI.put(XMLConstants.DEFAULT_NS_PREFIX, attributes.getValue(i));
                    } else {
                        nsToURI.put(localName, attributes.getValue(i));
                    }
                }
            }
        }

        if(!XMLConstants.NULL_NS_URI.equals(namespace)) {
            String[] qNameTokens = qName.split(":");
            String prefix;

            if(qNameTokens.length == 1) {
                prefix = XMLConstants.DEFAULT_NS_PREFIX;
            } else {
                prefix = qNameTokens[0];
            }

            if (!prefixAlreadyDeclared(prefix) && !nsToURI.containsKey(prefix)) {
                if(nsToURI == Collections.EMPTY_MAP) {
                    nsToURI = new LinkedHashMap<String, String>();
                }
                nsToURI.put(prefix, namespace);
            }
        }

        if(!nsToURI.isEmpty() && !readerStack.isEmpty()) {
            Set<Map.Entry<String,String>> namespaces = nsToURI.entrySet();

            // Now call start prefixes if namespaces are not empty
            ContentHandler contentHandler = readerStack.peek().getContentHandler();
            if (contentHandler != null) {
                for (Map.Entry<String,String> ns : namespaces) {
                    contentHandler.startPrefixMapping(ns.getKey(), ns.getValue());
                }
            }
        }

        namespaceStack.push(nsToURI);

        return attributes;
  }

    /**
     * Pop element out of the namespace declaration stack and notifying
     * {@link ContentHandler} if required.
     *
     * @throws SAXException
     */
    public void popNamespaces() throws SAXException {
        Map<String, String> namespaces = namespaceStack.pop();

        if (!namespaces.isEmpty() && !readerStack.isEmpty()) {
            Set<String> nsPrefixes = namespaces.keySet();

            ContentHandler contentHandler = readerStack.peek().getContentHandler();
            if (contentHandler != null) {
                for (String prefix : nsPrefixes) {
                        contentHandler.endPrefixMapping(prefix);
                }
            }
        }
    }

    /**
     * Push a new XMLReader instance onto the XMLReader Stack.
     * @param reader The reader instance.
     */
    public void pushReader(XMLReader reader) {
        readerStack.push(reader);
    }

    /**
     * Pop the current XMLReader off the XMLReader stack.
     * @return The reader instance that was popped from the stack.
     */
    public XMLReader popReader() {
        return readerStack.pop();
    }

    public String getPrefix(String uri) {
        int stackDepth = namespaceStack.size();

        for (int i = stackDepth - 1; i >= 0; i--) {
            Map<String, String> nsMap = namespaceStack.get(i);

            if(!nsMap.isEmpty()) {
                Set<Map.Entry<String,String>> nsEntries = nsMap.entrySet();
                for (Map.Entry<String,String> nsEntry : nsEntries) {
                    if(nsEntry.getValue().equals(uri)) {
                        return nsEntry.getKey();
                    }
                }
            }
        }

        return null;
    }

    public Map<String, String> getActiveNamespaces() {
        Map<String, String> activeNamespaces = new HashMap<String, String>();
        int stackDepth = namespaceStack.size();

        for (int i = stackDepth - 1; i >= 0; i--) {
            Map<String, String> nsMap = namespaceStack.get(i);

            if(!nsMap.isEmpty()) {
                activeNamespaces.putAll(nsMap);
            }
        }

        return activeNamespaces;
    }

    public String getUri(String getKey) {
        int stackDepth = namespaceStack.size();

        for (int i = stackDepth - 1; i >= 0; i--) {
            Map<String, String> nsMap = namespaceStack.get(i);

            if(!nsMap.isEmpty()) {
                Set<Map.Entry<String,String>> nsEntries = nsMap.entrySet();
                for (Map.Entry<String,String> nsEntry : nsEntries) {
                    if(nsEntry.getKey().equals(getKey)) {
                        return nsEntry.getValue();
                    }
                }
            }
        }

        return null;
    }

    /**
     * This method returns true if namespace with given prefix was already declared higher
     * the stack
     *
     * @param prefix
     * @return
     */
    private boolean prefixAlreadyDeclared(String prefix) {
        for (Map<String, String> set : namespaceStack) {
            if (set.containsKey(prefix)) {
                return true;
            }
        }
        return false;
    }
}
TOP

Related Classes of org.milyn.namespace.NamespaceDeclarationStack

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.