com.swtxml.tinydom.TinyDomSaxHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.swtxml.tinydom.TinyDomSaxHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2008 Ralf Ebert
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Ralf Ebert - initial API and implementation
 *******************************************************************************/
package com.swtxml.tinydom;

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

import org.apache.commons.lang.StringUtils;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.swtxml.definition.IAttributeDefinition;
import com.swtxml.definition.INamespaceDefinition;
import com.swtxml.definition.INamespaceResolver;
import com.swtxml.definition.ITagDefinition;
import com.swtxml.definition.ITagScope;
import com.swtxml.util.lang.CollectionUtils;
import com.swtxml.util.parser.ParseException;

public class TinyDomSaxHandler extends DefaultHandler {

    private final String xmlFilename;
    private Locator locator;
    private Tag root;
    private final INamespaceResolver namespaceResolver;
    private final Map<String, INamespaceDefinition> namespaces = new HashMap<String, INamespaceDefinition>();

    TinyDomSaxHandler(INamespaceResolver namespaceResolver, String xmlFilename) {
        this.namespaceResolver = namespaceResolver;
        this.xmlFilename = xmlFilename;
    }

    private Stack<Tag> parserStack = new Stack<Tag>();

    @Override
    public void startElement(String namespace, String localName, String qName, Attributes attributes)
            throws SAXException {
        INamespaceDefinition namespaceDefinition = getNamespace(namespace);
        ITagDefinition tagDefinition = namespaceDefinition.getTag(localName);
        if (tagDefinition == null) {
            throw new ParseException("Unknown tag \"" + localName + "\" for namespace \"" + namespace
                    + "\", allowed are: " + CollectionUtils.sortedToString(namespaceDefinition.getTagNames()));
        }
        Map<INamespaceDefinition, Map<IAttributeDefinition, String>> attributeMap = processAttributes(
                namespaceDefinition, tagDefinition, attributes);

        Tag tag = new Tag(namespaceDefinition, tagDefinition, attributeMap,
                parserStack.isEmpty() ? null : parserStack.peek(), getLocationInfo());

        ITagDefinition parentTag = tag.getParent() != null ? tag.getParent().getTagDefinition()
                : ITagDefinition.ROOT;
        if (tagDefinition instanceof ITagScope && !((ITagScope) tagDefinition).isAllowedIn(parentTag)) {
            throw new ParseException("Tag " + tag.getName() + " is not allowed in " + parentTag.getName());
        }

        if (root == null) {
            this.root = tag;
        }
        parserStack.push(tag);
    }

    private Map<INamespaceDefinition, Map<IAttributeDefinition, String>> processAttributes(
            INamespaceDefinition tagNamespace, ITagDefinition tagDefinition, Attributes attributes) {

        Map<INamespaceDefinition, Map<IAttributeDefinition, String>> attributeNsMap = new HashMap<INamespaceDefinition, Map<IAttributeDefinition, String>>();
        for (int i = 0; i < attributes.getLength(); i++) {
            String uri = attributes.getURI(i);
            INamespaceDefinition attributeNamespace = !StringUtils.isEmpty(uri) ? getNamespace(uri) : tagNamespace;
            Map<IAttributeDefinition, String> attributeMap = attributeNsMap.get(attributeNamespace);
            if (attributeMap == null) {
                attributeMap = new HashMap<IAttributeDefinition, String>();
                attributeNsMap.put(attributeNamespace, attributeMap);
            }
            String name = attributes.getLocalName(i);
            String value = attributes.getValue(i);
            IAttributeDefinition attributeDefinition;
            if (attributeNamespace.equals(tagNamespace)) {
                attributeDefinition = tagDefinition.getAttribute(name);
            } else {
                attributeDefinition = attributeNamespace.getForeignAttribute(name);
                if (attributeDefinition instanceof ITagScope
                        && !((ITagScope) attributeDefinition).isAllowedIn(tagDefinition)) {
                    throw new ParseException("Attribute " + attributes.getQName(i) + " is not allowed for tag \""
                            + tagDefinition.getName() + "\"");
                }
            }

            if (attributeDefinition == null) {
                throw new ParseException("Unknown attribute \"" + attributes.getQName(i) + "\" for tag \""
                        + tagDefinition.getName() + "\" (available are: "
                        + CollectionUtils.sortedToString(tagDefinition.getAttributeNames()) + ")");
            }
            attributeMap.put(attributeDefinition, value);

        }
        if (attributeNsMap.isEmpty()) {
            return Collections.emptyMap();
        }
        return attributeNsMap;
    }

    private INamespaceDefinition getNamespace(String namespaceUri) {
        INamespaceDefinition namespace = namespaces.get(namespaceUri);
        if (namespace == null) {
            namespace = namespaceResolver.resolveNamespace(namespaceUri);
            if (namespace == null) {
                throw new ParseException("Unknown namespace: " + namespaceUri);
            }
            namespaces.put(namespaceUri, namespace);
        }
        return namespace;
    }

    public String getLocationInfo() {
        return xmlFilename + ((locator != null) ? " [line " + locator.getLineNumber() + "] " : "");
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        parserStack.pop();
    }

    @Override
    public void setDocumentLocator(Locator locator) {
        this.locator = locator;
    }

    public Tag getRoot() {
        return root;
    }
}