All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.centurylink.mdw.xml.XmlPath Maven / Gradle / Ivy

There is a newer version: 6.1.39
Show newest version
/*
 * Copyright (C) 2017 CenturyLink, Inc.
 *
 * 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.
 */
package com.centurylink.mdw.xml;

//import java.util.HashMap;
//import java.util.Map;

import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor.XmlBookmark;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * 
 * XmlPath
 * 
 * This class wraps around name-space agnostic XPath
 * 
 * @version 1.0
 */
public class XmlPath {
    
    private String path_string; // for parsing
    private int n;      // for parsing - string length of path_string
    private int k;      // for parsing - next char position;
    private PathSegment path_seg;   // result of parsing
    
    public XmlPath(String path_string) throws XmlException {
        this.path_string = path_string;
        n = path_string.length();
        k = 0;
        Token token = getNextToken();
        if (token!=null && token.kind==TokenKind.SLASH) token = getNextToken(); // ignore initial slash
        path_seg = parse_path_segment(token);  
    }

    /**
     * Using XPath or XQuery.
     * NOTE!!!! To use this code, need to include
     * xbean_xpath.jar, saxon9.jar, saxon9-dom.jar in CLASSPATH
     * in startWebLogic.cmd
     * @param xmlbean
     * @param path
     * @return
     */

    public static String evaluate(XmlObject xmlbean, String path) {
        XmlCursor cursor = xmlbean.newCursor();
        String value;
        
// 1.2.3. use XQuery or selectPath
//
//        cursor.toFirstChild();
//        String defaultNamespace = cursor.namespaceForPrefix("");
//        String namespaceDecl = "declare default element namespace '" + defaultNamespace + "';";
//        Map namespaces = new HashMap();
//        cursor.getAllNamespaces(namespaces);
//        for (String prefix : namespaces.keySet())
//        {
//            namespaceDecl += "declare namespace " + prefix + "='" + namespaces.get(prefix) + "';";
//        }
//  1. use XQuery
//        XmlCursor results = cursor.execQuery(namespaceDecl + path);
//        value = (results==null)?null:results.getTextValue();
        
//  2. use selectPath on XmlObject
//        XmlObject[] result = xmlbean.selectPath(namespaceDecl + path);
        
//  3. use selectPath on XmlCursor   
//        cursor.toParent();
//        XmlOptions options = new XmlOptions();
//        options.put(Path.PATH_DELEGATE_INTERFACE,"org.apache.xmlbeans.impl.xpath.saxon.XBeansXPath");
//        cursor.selectPath(namespaceDecl + path, options);
//        if (cursor.getSelectionCount()>0) {
//            cursor.toNextSelection();
//            value = cursor.getTextValue();
//        } else value = null;

// 4. use our own implementation
        try {
            XmlPath matcher = new XmlPath(path);
            value = matcher.evaluate_segment(cursor, matcher.path_seg);
        } catch (XmlException e) {
            value = null; // xpath syntax error - treated as no match
        }
        
        cursor.dispose();
        return value;
    }
    
    public String getHashBucket() {
        return path_seg.name==null?"*":path_seg.name;    // either a root element name or *
    }
    
    public static String getRootNodeName(Document reqdoc) {
        Node node = reqdoc.getFirstChild();
        while (node!=null && node.getNodeType()!=Node.ELEMENT_NODE) {
            node = node.getNextSibling();
        }
        return node==null?null:node.getNodeName();
    }

    public static String getRootNodeName(XmlObject xmlbean) {
        XmlCursor cursor = xmlbean.newCursor();
        cursor.toFirstChild();
        return cursor.getName().getLocalPart();
    }
    
    public static String getRootNodeValue(XmlObject xmlbean) {
        XmlCursor cursor = xmlbean.newCursor();
        cursor.toFirstChild();
        return cursor.getTextValue();
    }
    
    ////// our own implementation of namespace-agnostic XPath matcher 
    
    private static class Condition {
        String name;
        boolean isAttribute;
        String value;
    }
    
    private static class PathSegment {
        String name;            // special case: "*" - wild card; null - recursive descent
        Condition condition;
        PathSegment rest;
        boolean isAttribute;
    }
    
    enum TokenKind { NAME, AT, VALUE, EQ, LBRACKET, RBRACKET, SLASH, STAR };
    
    private static class Token {
        TokenKind kind;
        int start, end;
    }
    
    public String evaluate(XmlObject xmlbean) {
        XmlCursor cursor = xmlbean.newCursor();
        String value = evaluate_segment(cursor, path_seg);
        cursor.dispose();
        return value;
    }
    
    private static boolean isNameChar(char ch) {
        return ch==':' || ch=='-' || ch=='_' || Character.isLetterOrDigit(ch);
    }
    
    private Token getNextToken() throws XmlException {
        while (k=n) return null;
        char ch = path_string.charAt(k);
        Token token = new Token();
        token.start = k;
        token.end = k+1;
        switch (ch) {
        case '[': token.kind = TokenKind.LBRACKET; break;
        case ']': token.kind = TokenKind.RBRACKET; break;
        case '@': token.kind = TokenKind.AT; break;
        case '=': token.kind = TokenKind.EQ; break;
        case '*': token.kind = TokenKind.STAR; break;
        case '/': token.kind = TokenKind.SLASH; break;
        case '\'': token.kind = TokenKind.VALUE; getValueToken(token,'\''); break;
        case '"': token.kind = TokenKind.VALUE; getValueToken(token,'"'); break;
        default:
            if (isNameChar(ch)) {
                token.kind = TokenKind.NAME;
                getNameToken(token);
            } else {
                throw new XmlException("Invalid XPath Pattern: " + path_string);
            }
            break;
        }
        k = token.end;
        return token;
    }
    
    private void getNameToken(Token token) {
        int l = k+1;
        while (l© 2015 - 2025 Weber Informatics LLC | Privacy Policy