Package xbird.storage.indexer

Source Code of xbird.storage.indexer.XMLPathPattern

/*
* @(#)$Id$
*
* Copyright 2006-2008 Makoto YUI
*
* Licensed 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.
*
* Contributors:
*     Makoto YUI - initial implementation
*/
package xbird.storage.indexer;

import java.util.Stack;

import xbird.util.collections.ints.IntStack;
import xbird.util.string.StringUtils;
import xbird.util.xml.NamespaceBinder;
import xbird.xquery.misc.QNameUtil;
import xbird.xquery.misc.QNameTable.QualifiedName;

/**
*
* <DIV lang="en"></DIV>
* <DIV lang="ja"></DIV>
*
* @author Makoto YUI (yuin405+xbird@gmail.com)
*/
public final class XMLPathPattern {

    public static final int ELEMENT = 0x10, ATTRIBUTE = 0x20, TEXT = 0x40;
    private static final int MATCH = 0x01, WILDCARD = 0x02, SKIPPABLE = 0x04 | ELEMENT;
    private static final int ANYNODE = 0xf0 | WILDCARD, ELEM_WILDCARD = WILDCARD | ELEMENT,
            ATTR_WILDCARD = WILDCARD | ATTRIBUTE, TEXT_MATCH = MATCH | TEXT;

    private final IntStack types;
    private final Stack<QualifiedName> patterns;

    public XMLPathPattern() {
        this.types = new IntStack(8);
        this.patterns = new Stack<QualifiedName>();
    }

    public XMLPathPattern(final String pattern, final NamespaceBinder namespaces) {
        this();
        init(pattern, namespaces);
    }

    public void init(final String pattern, final NamespaceBinder namespaces) {
        final int ptnlen = pattern.length();
        final int last = ptnlen - 1;
        final StringBuilder tokens = new StringBuilder(ptnlen);
        for(int i = 0; i < ptnlen; i++) {
            final char c = pattern.charAt(i);
            if(c == '/') {
                if(i == last) {
                    throw new IllegalArgumentException("Illegal expression: " + pattern);
                }
                if(i != 0 && tokens.length() > 0) {
                    final String prev = tokens.toString();
                    tokens.setLength(0);
                    addComponent(prev, namespaces);
                }
                if(pattern.charAt(i + 1) == '/') { // handle '//'                   
                    addComponent(null, SKIPPABLE);
                    ++i;
                }
            } else {
                tokens.append(c);
            }
        }
        if(tokens.length() > 0) {
            addComponent(tokens.toString(), namespaces);
        }
    }

    public void addComponent(final QualifiedName qname, final int type) {
        types.push(type);
        patterns.push(qname);
    }

    private void addComponent(final String tokens, final NamespaceBinder namespaces) {
        final int tokenlen = tokens.length();
        if(tokenlen == 0) {
            throw new IllegalArgumentException();
        }
        if(tokens.charAt(0) == '@') {
            if(tokenlen < 2) {
                throw new IllegalArgumentException("Illegal as attribute pattern: " + tokens);
            }
            final String attname = tokens.substring(1);
            if(attname.equals("*")) {
                addComponent(null, ATTRIBUTE | WILDCARD);
            } else {
                QualifiedName qname = QNameUtil.parse(tokens, namespaces);
                addComponent(qname, ATTRIBUTE | MATCH);
            }
        } else {
            if(tokens.equals("*")) {
                addComponent(null, ELEM_WILDCARD | WILDCARD);
            } else if(tokens.equals("text()")) {
                addComponent(null, MATCH | TEXT);
            } else if(tokens.equals("node(")) {
                addComponent(null, ANYNODE);
            } else {
                QualifiedName qname = QNameUtil.parse(tokens, namespaces);
                addComponent(qname, MATCH | ELEMENT);
            }
        }
    }

    public void removeLastComponent() {
        types.pop();
        patterns.pop();
    }

    public boolean match(XMLPathPattern other) {
        return match(this, other, 0, 0);
    }

    private static boolean match(final XMLPathPattern verifyPattern, final XMLPathPattern targetPattern, int vi, int oi) {
        final IntStack verifyTypes = verifyPattern.types;
        final Stack<QualifiedName> verifyPatterns = verifyPattern.patterns;
        final IntStack otherTypes = targetPattern.types;
        final Stack<QualifiedName> otherPatterns = targetPattern.patterns;
        final int otherPtnlen = otherPatterns.size();
        final int verifyPtnlen = verifyPatterns.size();

        for(; vi < verifyPtnlen; vi++, oi++) {
            if(oi >= otherPtnlen) {
                return false;
            }
            final int verifyType = verifyTypes.elementAt(vi);
            if((verifyType & MATCH) == MATCH) {
                final int otherType = otherTypes.elementAt(oi);
                if((otherType & MATCH) != MATCH) {
                    throw new IllegalArgumentException("Comparing other pattern must be an AbstractPath"
                            + otherTypes.toString());
                }
                if(verifyType != otherType) {
                    return false;
                }
                if(verifyType == TEXT_MATCH) {
                    continue;
                }
                final QualifiedName otherName = otherPatterns.get(oi);
                final QualifiedName verifyName = verifyPatterns.get(vi);
                if(!verifyName.equals(otherName)) {
                    return false;
                }
            } else if(verifyType == ELEM_WILDCARD) {
                final int otherType = otherTypes.elementAt(oi);
                if((otherType & ELEMENT) != ELEMENT) {
                    return false;
                }
            } else if(verifyType == ATTR_WILDCARD) {
                final int otherType = otherTypes.elementAt(oi);
                if((otherType & ATTRIBUTE) != ATTRIBUTE) {
                    return false;
                }
            } else if(verifyType == SKIPPABLE) {
                if(++vi >= verifyPtnlen) {
                    return false;
                }
                for(; oi < otherPtnlen; oi++) {
                    if(match(verifyPattern, targetPattern, vi, oi)) {
                        return true;
                    }
                    // back track to ANY
                }
                return false;
            } else {
                throw new IllegalStateException("Illegal type: "
                        + StringUtils.toBitString(verifyType));
            }
        }
        return oi == otherPtnlen;
    }

    @Override
    public String toString() {
        final StringBuilder buf = new StringBuilder(128);
        final int ptnlen = patterns.size();
        for(int i = 0; i < ptnlen; i++) {
            buf.append('/');
            final QualifiedName qname = patterns.get(i);
            final int type = types.elementAt(i);
            if(qname == null) {
                if(type == SKIPPABLE) {
                    continue;
                } else if(type == TEXT) {
                    buf.append("text()");
                } else if(type == ELEM_WILDCARD) {
                    buf.append("*");
                } else if(type == ATTR_WILDCARD) {
                    buf.append("@*");
                } else {
                    throw new IllegalStateException("Illegal type was detected for a NULL qname: "
                            + StringUtils.toBitString(type));
                }
            } else {
                assert ((type & MATCH) == MATCH) : StringUtils.toBitString(type);
                buf.append(QNameUtil.toLexicalForm(qname));
            }
        }
        return buf.toString();
    }

}
TOP

Related Classes of xbird.storage.indexer.XMLPathPattern

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.