
com.dtrules.xmlparser.XMLTree Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2004-2011 DTRules.com, Inc.
*
* See http://DTRules.com for updates and documentation for the DTRules Rules Engine
*
* 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.dtrules.xmlparser;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
/**
* @author ps24876
*
*/
public class XMLTree {
public enum NodeType {
Root,
Header,
Comment,
Tag
};
public static interface NoteDifference {
void AttributeDiff(Node n);
void BodyDiff(Node n);
void AttributeBodyDiff(Node n);
void NewTag(Node n);
void DeletedTag(Node n);
}
public static class Node {
final private String name;
final private NodeType type;
final private HashMap attributes;
private ArrayList tags = new ArrayList();
private String body;
private Node parent;
public void print (String filename) throws Exception {
OutputStream f = new FileOutputStream(filename);
XMLPrinter xout = new XMLPrinter(f);
print(xout);
}
public void print (XMLPrinter xout){
String name = this.name.replaceAll(" ", "_");
xout.opentagStringMap(name, attributes);
if(body == null || body.length()==0){
for(Node tag : tags){
tag.print(xout);
}
}else{
xout.printdata(body);
}
xout.closetag();
}
/**
* Find a Node under this node with the given tagName. Return
* null if it isn't found.
*/
public Node findTag(String tagName){
return findTag(this,tagName);
}
/**
* Find the next Node in a subtree with the given name. Return
* null if it isn't found.
* @param subtree
* @param tagName
* @return
*/
private Node findTag(Node subtree, String tagName){
if (subtree.getName().equals(tagName)){
return subtree;
}
for(Node n : subtree.getTags()){
Node f = findTag(n,tagName);
if(f != null){
return f;
}
}
return null;
}
public Node( String name, NodeType type, HashMap attribs, Node parent){
this.type = type;
this.parent = parent;
this.attributes = attribs;
this.name = name;
}
public enum MATCH {
match, // Node matches in every way.
differentType, // Type Node is different
differentBody, // Type is the same, but the body is different
differentAttributes, // Type is the same, but attributes are different
differentBodyAttributes, // Type is the same, but the body and the attributes are different
}
private String fix(String s, boolean whitespace ){
if(s==null)return "";
if(whitespace)return s;
s = s.trim().replaceAll("[\r\n\t]"," ");
while(s.indexOf(" ")>=0) {
s = s.replaceAll(" "," ");
}
return s;
}
/**
* Compares this node to another node. If they are exactly the same, we return true. Otherwise
* we return false. If whitespace is true, we insist whitespace matches; Otherwise we disregard
* differences in line breaks and spaces (reducing all white space to a single space before the
* compare).
*
* @param n
* @param whitespace
* @return code
*/
public MATCH compareToNode(Node n, boolean whitespace){
if(!type.equals(n.getType())){ // If not the same type, it makes no sense to
return MATCH.differentType; // compare further...
}
boolean attribs = compareAttributes(this.attributes,n.getAttributes()) &&
compareAttributes(n.attributes ,this.getAttributes());
boolean body = fix(this.body,whitespace).equals(fix(n.getBody(),whitespace));
if(attribs && body ) {
return MATCH.match;
}
if(!body && !attribs ){
return MATCH.differentBodyAttributes;
}
if(!body){
return MATCH.differentBody;
}
return MATCH.differentAttributes; // Only case that remains...
}
/**
* Compare the attributes of two nodes
* @param a1
* @param a2
* @return
*/
private boolean compareAttributes(HashMap a1, HashMap a2){
for(String key : a1.keySet()){
String v1 = a1.get(key);
String v2 = a2.get(key);
if(v2==null) return false;
if(!v1.equals(v2)) return false;
}
return true;
}
/**
* Compares two node trees to see if they are exactly equal
* @param n
* @param whitespace
* @return
*/
public boolean absoluteMatch(Node n, boolean whitespace){
if(compareToNode(n,whitespace) != MATCH.match){
return false;
}
if(tags.size() != n.getTags().size()){
return false;
}
for(int i=0;i getAttributes() {
return attributes;
}
/**
* @return the tags
*/
public ArrayList getTags() {
return tags;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return name.hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
String list=" ";
for(String v : attributes.keySet()){
list += v +"='"+attributes.get(v)+"' ";
}
return name+list;
}
}
private static class Loader implements IGenericXMLParser2 {
private Node root = new Node("root node",NodeType.Root, new HashMap(), null);
private boolean keepComments;
private boolean keepHeader;
Loader(boolean keepComments, boolean keepHeader){
this.keepComments = keepComments;
this.keepHeader = keepHeader;
}
private Node currentTag = root;
public void beginTag(String[] tagstk, int tagstkptr, String tag,
HashMap attribs) throws IOException, Exception {
Node n = new Node(tag, NodeType.Tag, attribs, currentTag);
currentTag.addTag(n);
currentTag = n;
}
public void endTag(String[] tagstk, int tagstkptr, String tag,
String body, HashMap attribs) throws Exception,
IOException {
currentTag.body = body;
currentTag = currentTag.parent;
}
public boolean error(String v) throws Exception {
return false;
}
public void comment(String comment) {
if(!keepComments) return;
Node c = new Node("comment node",NodeType.Comment,new HashMap(), currentTag);
c.body = comment;
c.addTag(c);
}
public void header(String header) {
if(!keepHeader) return;
Node c = new Node("header node", NodeType.Header,new HashMap(), currentTag);
c.body = header;
c.addTag(c);
}
Node loadStream(InputStream s) throws Exception {
GenericXMLParser.load(s,this);
return root;
}
}
static public Node BuildTree(String filename, boolean keepHeader, boolean keepComments) throws Exception {
FileInputStream f = new FileInputStream(filename);
return BuildTree(f, keepHeader, keepComments);
}
/**
* Returns null if the inputStream provided isn't an XML file, or some other unexpected Exception
* is thrown.
* @param f
* @param keepHeader
* @param keepComments
* @return
* @throws Exception
*/
static public Node BuildTree(InputStream f, boolean keepHeader, boolean keepComments) {
try {
Loader l = new Loader(keepComments, keepHeader);
return l.loadStream(f);
}catch(Exception e){
return null;
}
}
/**
* Bubble sort with quick out. Very fast on previously sorted data
* and pretty fast on nearly sorted data.
* @param array
*/
public static void sortByAttribute(boolean ascending, ArrayList nodes, String attribute){
int fence = nodes.size()-1;
boolean sorted = false;
for(int i=0; i < fence && !sorted ; i++){
for(int j = 0; j < fence-i; j++){
Node jth = nodes.get(j);
Node jplusOne = nodes.get(j+1);
if( jth.getAttributes().get(attribute).toString().compareTo(
jplusOne.getAttributes().get(attribute).toString())>0 ^ !ascending){
sorted = false;
nodes.set(j,jplusOne);
nodes.set(j+1,jth);
}
}
}
}
private static boolean match(Node n1, Node n2, String[] attribs){
if(n1.getName()!=n2.getName())return false;
for(int i=0; i removeDuplicates(ArrayList nodes, String[] attribs){
ArrayList dups = new ArrayList();
for(int i=0; i < nodes.size() ; i++){
for(int j = nodes.size()-1;j>i; j--){ // go backwards on j, so we can remove jth if a dup
Node ith = nodes.get(i);
Node jth = nodes.get(j);
if(match(ith,jth,attribs)){
nodes.remove(j);
dups.add(jth);
}
}
}
return dups;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy