//*********************************************************************************
// class tig.xml.DomDoc
// Software released under the General Public License (version 2 or later), available at
// http://www.gnu.org/copyleft/gpl.html
//*********************************************************************************
package tig.xml;

import tig.GeneralConstants;
import tig.Strings;
import org.w3c.dom.*;
import java.util.regex.*;
import java.util.Vector;

/******************************************************************************
Wrapps a org.w3c.dom.Document, providing easy access to the document's contents.

Usage of this class is based on the notion of current path of an element, which describes its path to root node, using "/" as separator and the names of the node's ancestors.
For example, with the XML structure :
<rootNode>
  <elt1>
    <elt2>
      <elt3/>
    </elt2>
  </elt1>
</rootNode>
the current path of elt3 is "rootNode/elt1/elt2".
So you specify which part of the document you want to access with setCurrentPath(), and then use the other methods.
If the path is not set, it is considered as "", which is the path to root node. So the results are obtained for the whole document. @author Thierry Graff @history apr 13 2002 : creation. @todo homogeneity of return between getAttributeValue and getAttributesValues (null Exception) @todo shorten test methods. @todo find a way to introduce regExp in getAttributesValues(String, String[]). @todo use Node.getNodeName() for currentPath??? *********************************************************************************/ public class DomDoc implements GeneralConstants{ //================================================================================= // INSTANCE VARIABLES //================================================================================= private Document _doc; private String _curPath; private int _regExMode; //================================================================================= // CONSTANTS //================================================================================= private final static String SLASH = "/"; private final static String WILDCARD = "*"; private final static String POINT_WILDCARD = ".*"; /** Constant indicating that regular expressions (in {@link #getAttributesValues(String,String)}) are interpreted the standard way.
Used with {@link #setRegExMode(int)}. */ public static final int REGEX_NORMAL = 0; /** Constant indicating that regular expressions (in {@link #getAttributesValues(String,String)}) are modified before being interpreted : wildcards ('*') are changed to '.*'. This mode permits to consider that the '*' is equivalent to any sequence of characters. Used with {@link #setRegExMode(int)}.
This is the defalut mode. */ public static final int REGEX_WILDCARD_ONLY = 1; //================================================================================= // CONSTRUCTORS //================================================================================= /** Unique constructor. @param doc the DOM Document used to handle internally the data. */ public DomDoc(Document doc){ _doc = doc; _curPath = BLANK; _regExMode = REGEX_WILDCARD_ONLY; }// end constructor //================================================================================= // METHODS //================================================================================= //*************** get / set currentPath *************** /** Sets the "current path". See class documentation for more information. */ public void setCurrentPath(String path){ _curPath = path; } /** Returns the "current path". See class documentation for more information. */ public String getCurrentPath(){ return _curPath; } //*************** get / set Document *************** /** Sets the Document that this DomDoc is wrapping. The current path is set to empty String (root node). */ public void setDocument(Document doc){ _doc = doc; _curPath = BLANK; } /** Returns the Document that this DomDoc is wrapping. */ public Document getDocument(){ return _doc; } //*************** setRegExMode *************** /** Sets the "regular expression mode" ; see REGEX_XXX constants. */ public void setRegExMode(int regExMode){ _regExMode = regExMode; } //*************** getAttributeValue *************** /** Method to get the value of an attribute of a tag of current path.
Convenient if the document contains one and only one tag 'tagName' ; this tag must have an attribute 'attributeName'. Written to directly get a String.
Example :
  <myXmlDoc>
    ...
    <theTag theAttribute = "theValue">
    ...
  </myXmlDoc>
The call getAttributeValue(theTag, theAttribute) will return "theValue".

This method is sensitive to last call to {@link #setCurrentPath(String)}

To retrieve attribute values of several tags, or several attribute values of a tag, use {@link #getAttributesValues(String,String[])}. @return The value of the specified attribute if one is found - Also works if the doc contains several pairs {tag, attribute}. In this case, the first tag encountered is returned.
Returns null in the following cases :
  • if 'tagName' or 'attributeName' is null ;
  • if the document contains more than one tag 'tagName' ;

  • if there is no such pair {tag, attribute} (tag or attribute not found). */ public String getAttributeValue(String tagName, String attributeName){ // Parameter checking //if (tagName == null) throw new IllegalArgumentException("Argument 'tagName' can't be null."); //if (attributeName == null) throw new IllegalArgumentException("Argument 'attributeName' can't be null."); if (tagName == null || attributeName == null) return null; NodeList nodeList; Node node; NamedNodeMap nnm; int len; nodeList = _doc.getElementsByTagName(tagName); len = nodeList.getLength(); if(len == 0) return null; // Find the first element of the list corresponding to current path. int curIndex = 0; while(!belongsToPath(nodeList.item(curIndex), _curPath)) curIndex++; node = nodeList.item(curIndex); nnm = node.getAttributes(); if(nnm == null){ //sendError("Error : tag " + tagName + " must have one attribute " + attributeName + "."); return null; } else{ for(int i = 0; i < nnm.getLength(); i++){ node = nnm.item(i); if(node.getNodeName().equals(attributeName)) return node.getNodeValue(); } } //sendError("Error : tag " + tagName + " must have one attribute " + attributeName + "."); return null; }// end getAttributeValue //*************** getAttributesValues(String, String[]) *************** /** Method to get the values of tags attributes. Return results for tags of the current path.
    This method can be used to retrieve the attribute values of tags named 'tagName'.
    Example :
      <myXmlDoc>
        ...
        <theTag attr1 = "val1.1" attr2 = "val1.2" attr3="val1.3"/>
        <theTag attr1 = "val2.1" attr3="val2.3"/>
        <theTag attr1 = "val3.1" attr2 = "val3.2" attr3="val3.3"/>
        ...
      </myXmlDoc>
      
    The code :
        String[] attributeNames = new String[]{"attr1", "attr2"};
        getAttributesValues("theTag", attributeNames);
      
    will return a String[] containing :
      {
        {"val1.1", "val1.2"},
        {"val2.1", null},
        {"val3.1", "val3.2"}
      }
      
    @return the list as specified above or null if the document doesn't contain 'tagName' tags.
    If attributes are missing, null is put to the corresponding place of the the resulting array.
    Returns null if parameter 'tagName' is null, if 'attributeNames' is null or empty */ public String[][] getAttributesValues(String tagName, String[] attributeNames) throws Exception{ // Parameter checking if (tagName == null || attributeNames == null || attributeNames.length == 0) return null; //if (tagName == null) throw new IllegalArgumentException("Argument 'tagName' can't be null."); //if (attributeNames == null) throw new IllegalArgumentException("Argument 'attributeNames' can't be null."); NodeList nodeList; Node node; NamedNodeMap nnm; Vector res = new Vector(); // method : get all the 'tagName' tags ; add in the Vector only those in the current path // and build a String[][] from the Vector nodeList = _doc.getElementsByTagName(tagName); int nlSize = nodeList.getLength(); if(nlSize == 0) return null; int nbAttrs = attributeNames.length; // Loop on the tags of the nodeList for(int i = 0; i < nlSize; i++){ node = nodeList.item(i); if(!belongsToPath(nodeList.item(i), _curPath)) continue; String[] attrs = new String[nbAttrs]; nnm = node.getAttributes(); // Loop on the attributes for(int j = 0; j < nnm.getLength(); j++){ node = nnm.item(j); // Loop on parameter 'attributeNames' for(int k = 0; k < attributeNames.length; k++){ if(node.getNodeName().equals(attributeNames[k])) attrs[k] = node.getNodeValue(); }// end for k }// end for j res.add(attrs); }// end for i int nbTags = res.size(); if(nbTags == 0) return null; String[][] res2 = new String[nbTags][nbAttrs]; for(int i = 0; i < nbTags; i++){ res2[i] = (String[])res.get(i); } return res2; }// end getAttributesValues(String, String[]) //*************** getAttributesValues(String, String) *************** /** Equivalent to {@link #getAttributesValues(String,String[])} when 'attributeNames' contains only element, or when a regular expression is used to designate the attribute names.
    The most common use of regular expressions is to use a wildcard ('*') to replace any sequence of character. For more details, see documentation of class java.util.regex.Pattern.
    WARNING : the returned array is not filled with 'null' if the match is not found, like in {@link #getAttributesValues(String,String[])}.
    Example :
      <myXmlDoc>
        ...
        <theTag attr1 = "val1.1" attr2 = "val1.2" attr3="val1.3"/>
        <theTag attr1 = "val2.1" attr3="val2.3"/>
        <theTag attr1 = "val3.1" attr2 = "val3.2" attr3="val3.3"/>
        ...
      </myXmlDoc>
      
    The code :
        getAttributesValues("theTag", "attr*");
      
    will return a String[] containing :
      {
        {"val1.1", "val1.2", "val1.3"},
        {"val2.1", "val2.3"},
        {"val3.1", "val3.2", "val3.3"}
      }
      
    */ public String[][] getAttributesValues(String tagName, String attributeNames){ // Parameter checking if (tagName == null || attributeNames == null) return null; //if (tagName == null) throw new IllegalArgumentException("Argument 'tagName' can't be null."); //if (attributeNames == null) throw new IllegalArgumentException("Argument 'attributeNames' can't be null."); // modify 'attributeNames' depending on regExMode if(_regExMode == REGEX_WILDCARD_ONLY) attributeNames = Strings.replace(attributeNames, WILDCARD, POINT_WILDCARD); NodeList nodeList; Node node; NamedNodeMap nnm; int len; Vector res = new Vector(); Pattern pattern = Pattern.compile(attributeNames); //Matcher matcher; // method : get all the 'tagName' tags ; add in the Vector only those in the current path // and build a String[][] from the Vector nodeList = _doc.getElementsByTagName(tagName); int nlSize = nodeList.getLength(); //System.out.println("nlSize = " + nlSize); if(nlSize == 0) return null; // Loop on the tags of the nodeList for(int i = 0; i < nlSize; i++){ node = nodeList.item(i); if(!belongsToPath(nodeList.item(i), _curPath)) continue; Vector attrs = new Vector(); nnm = node.getAttributes(); // Loop on the attributes //System.out.println("nb attrs = " + nnm.getLength()); for(int j = 0; j < nnm.getLength(); j++){ node = nnm.item(j); // check if the attribute matches the pattern Matcher matcher = pattern.matcher(node.getNodeName()); if(matcher.matches()) attrs.add(node.getNodeValue()); //System.out.println(" attr = " + node.getNodeValue() + " - match = " + (matcher.matches() ? "YES" : "NO")); }// end for j res.add(attrs); }// end for i // Transform to a String[][] int nbTags = res.size(); Vector curV; if(nbTags == 0) return null; String[][] res2 = new String[nbTags][]; for(int i = 0; i < nbTags; i++){ curV = (Vector)res.get(i); len = curV.size(); res2[i] = new String[len]; for(int j = 0; j < len; j++) res2[i][j] = (String)curV.get(j); } return res2; }// end getAttributesValues(String, String) //================================================================================= // STATIC METHODS //================================================================================= //******************************************************** // METHOD TO PUT ELSEWHERE private static void sendError(String str) throws Exception{ throw new Exception(str); } //******************************************************** /** Returns a String representing the path of a node.
    The String is built with the names of the parent nodes separated by "/". */ public static String getPath(Node node){ if(node == null) throw new IllegalArgumentException("getPath can't be called with a null node"); StringBuffer path = new StringBuffer(); Vector parentNames = new Vector(); Node curNode = node.getParentNode(); // start to build the path with the parent node if(curNode == null) return BLANK; while(curNode.getParentNode() != null){ parentNames.add(curNode.getNodeName()); curNode = curNode.getParentNode(); } int n = parentNames.size(); for(int i = 0; i < n; i++){ path.append((String)(parentNames.elementAt(n - 1 - i))); if (i < n - 1) path.append(SLASH); } return path.toString(); }// end getPath //******************************************************** /** Indicates if a node belongs to a given path. */ public static boolean belongsToPath(Node node, String path){ if(node == null) throw new IllegalArgumentException("belongsToPath can't be called with a null node"); if(path == null) throw new IllegalArgumentException("belongsToPath can't be called with a null path"); if(path.equals(BLANK)) return true; // Transform the paths to arrays. String[] aPath = Strings.stringToStringArray(path, '/'); String[] aNodePath = Strings.stringToStringArray(getPath(node), '/'); int pathLen = aPath.length; int nodePathLen = aNodePath.length; if (nodePathLen < pathLen) return false; boolean res = true; for(int i = 0; i < pathLen; i++){ if(!aPath[i].equals(aNodePath[i])) res = false; } return res; }// end belongsToPath //================================================================================= //================================================================================= // TESTS //================================================================================= //================================================================================= // **************** For tests only **************** public static void main(String[] args){ // no complete argument checking if(args[0].equalsIgnoreCase("testGetAttributeValue")) testGetAttributeValue(args[1], args[2], args[3]); else if(args[0].equalsIgnoreCase("testGetAttributesValues")) testGetAttributesValues(args[1], args[2], args[3]); else if(args[0].equalsIgnoreCase("testGetAttributesValues2")) testGetAttributesValues2(args[1], args[2], args[3]); else{ String possibleArgs = "'testGetAttributeValue' or 'testGetAttributesValues' or 'testGetAttributesValues2'"; System.out.println("first argument must be " + possibleArgs); } }// end main // **************** For tests only **************** //D:\Programs\java\jdk1.4\bin\java -classpath .;bin tig.xml.DOMDocument testGetAttributeValue test.xml trail name private static void testGetAttributeValue(String xmlFile, String tagName, String attrName){ try{ // Build the document javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); javax.xml.parsers.DocumentBuilder builder = factory.newDocumentBuilder(); Document doc; doc = builder.parse( new java.io.File(xmlFile) ); // test the method DomDoc domDoc = new DomDoc(doc); System.out.println(domDoc.getAttributeValue(tagName, attrName)); } catch(org.xml.sax.SAXParseException spe){ System.out.println("Parse error occured - line " + spe.getLineNumber() + " col " + spe.getColumnNumber() + " :"); spe.printStackTrace(); } catch(Exception e){ e.printStackTrace(); } }// end testGetAttributeValue // **************** For tests only **************** private static void testGetAttributesValues(String xmlFile, String tagName, String attrNames){ try{ // Build the document javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); javax.xml.parsers.DocumentBuilder builder = factory.newDocumentBuilder(); Document doc; doc = builder.parse( new java.io.File(xmlFile) ); // test the method DomDoc domDoc = new DomDoc(doc); // build attrNames from the parameter String[] attrNames2 = tig.Strings.stringToStringArray(attrNames); // call the method and trace String[][] res = domDoc.getAttributesValues(tagName, attrNames2); for(int i = 0; i < res.length; i++){ for(int j = 0; j < res[i].length; j++){ if(res[i][j] != null) System.out.println("res[" + i + "][" + j + "] = " + res[i][j]); else System.out.println("res[" + i + "][" + j + "] = null"); } } } catch(org.xml.sax.SAXParseException spe){ System.out.println("Parse error occured - line " + spe.getLineNumber() + " col " + spe.getColumnNumber() + " :"); spe.printStackTrace(); } catch(Exception e){ e.printStackTrace(); } }// end testGetAttributesValues // **************** For tests only **************** // tests the (String, String) version private static void testGetAttributesValues2(String xmlFile, String tagName, String attrNames){ try{ // Build the document javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); javax.xml.parsers.DocumentBuilder builder = factory.newDocumentBuilder(); Document doc; doc = builder.parse( new java.io.File(xmlFile) ); // test the method DomDoc domDoc = new DomDoc(doc); // build attrNames from the parameter // call the method and trace String[][] res = domDoc.getAttributesValues(tagName, attrNames); for(int i = 0; i < res.length; i++){ for(int j = 0; j < res[i].length; j++){ if(res[i][j] != null) System.out.println("res[" + i + "][" + j + "] = " + res[i][j]); else System.out.println("res[" + i + "][" + j + "] = null"); } } } catch(org.xml.sax.SAXParseException spe){ System.out.println("Parse error occured - line " + spe.getLineNumber() + " col " + spe.getColumnNumber() + " :"); spe.printStackTrace(); } catch(Exception e){ e.printStackTrace(); } }// end testGetAttributesValues2 }// end class DomDoc

    Ads help maintain this website.