srcanaapps/apiquerytool/com.nokia.s60tools.apiquery/src/com/nokia/s60tools/apiquery/shared/util/xml/XMLDataSAXHandler.java
changeset 0 a02c979e8dfd
equal deleted inserted replaced
-1:000000000000 0:a02c979e8dfd
       
     1 /*
       
     2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17  
       
    18 package com.nokia.s60tools.apiquery.shared.util.xml;
       
    19 
       
    20 import java.util.EmptyStackException;
       
    21 import java.util.LinkedHashMap;
       
    22 import java.util.ListIterator;
       
    23 import java.util.Map;
       
    24 import java.util.Set;
       
    25 import java.util.Stack;
       
    26 import java.util.Vector;
       
    27 
       
    28 import org.xml.sax.Attributes;
       
    29 import org.xml.sax.SAXException;
       
    30 import org.xml.sax.SAXParseException;
       
    31 import org.xml.sax.helpers.DefaultHandler;
       
    32 
       
    33 import com.nokia.s60tools.apiquery.shared.resources.Messages;
       
    34 import com.nokia.s60tools.apiquery.shared.util.console.APIQueryConsole;
       
    35 import com.nokia.s60tools.util.debug.DbgUtility;
       
    36 
       
    37 /**
       
    38  * SAX parser callback class that parses the XML into
       
    39  * into XMLElementData object array. The set of elements
       
    40  * and attributes to be parsed are specified in constructor.
       
    41  * 
       
    42  * This class can parse elements that do not themselves contain 
       
    43  * any child elements. I.e. the elements to be parsed must be 
       
    44  * of flat XML. The parsed elements themselves can, of course, 
       
    45  * be contained by some parent element(s) that are not parsed 
       
    46  * by this handler.
       
    47  */
       
    48 public class XMLDataSAXHandler extends DefaultHandler{
       
    49 
       
    50 	/**
       
    51 	 * Set of element names we are interested in.
       
    52 	 * Other elements are ignored.
       
    53 	 */
       
    54 	private final Set<String> elemNameSet;
       
    55 	
       
    56 	/**
       
    57 	 * Vector for storing the parsed elements.
       
    58 	 */
       
    59 	private final Vector<XMLElementData> parsedElementsVector;
       
    60 	
       
    61 	/**
       
    62 	 * Flag is set to true when we are inside an element that is recognized.
       
    63 	 */
       
    64 	private boolean isInsideAcceptedElement = false;
       
    65 	
       
    66 	/**
       
    67 	 * Name for the element currently under parsing.
       
    68 	 */
       
    69 	private String parsedElementName = null;
       
    70 	
       
    71 	/**
       
    72 	 * Value for the element currently under parsing.
       
    73 	 */
       
    74 	private String parsedElementValue = null;
       
    75 
       
    76 	/**
       
    77 	 * Array for storing attribute data found for the element.
       
    78 	 */
       
    79 	private Map<String, String> parsedAttributeData = null;
       
    80 	
       
    81 	/**
       
    82 	 * Element -> Attribute set map containg attributes
       
    83 	 * that should be checked for the element.
       
    84 	 */
       
    85 	private final Map<String, Map<String, String>> attributeMap;
       
    86 
       
    87 	/**
       
    88 	 * Parent restrictions for the elements.
       
    89 	 */
       
    90 	private final Map<String, String> parentElementRestrictionMap;	
       
    91 
       
    92 	/**
       
    93 	 * Storing elements to stack in order to resolve parent
       
    94 	 * for the current element.
       
    95 	 */
       
    96 	private final Stack<String> elementStack;	
       
    97 
       
    98 	/**
       
    99 	 * Constructor.
       
   100 	 * @param elemNameSet Set of element names that this handler
       
   101 	 *                    will take into account.
       
   102 	 * @param attributeMap Element -> Attribute set map containg attributes
       
   103 	 *                     that should be checked for the element.
       
   104 	 * @param parentElementRestrictionMap Parent element restrictions for parsing.
       
   105 	 */
       
   106 	public XMLDataSAXHandler(Set<String> elemNameSet, Map<String,Map<String, String>> attributeMap, 
       
   107 			                 Map<String, String> parentElementRestrictionMap){
       
   108 		this.elemNameSet = elemNameSet;
       
   109 		this.attributeMap = attributeMap;
       
   110 		this.parentElementRestrictionMap = parentElementRestrictionMap;
       
   111 		parsedElementsVector = new Vector<XMLElementData>();
       
   112 		parsedAttributeData = new LinkedHashMap<String, String>(); 
       
   113 		elementStack = new Stack<String>();	
       
   114 	}
       
   115 
       
   116 	/* (non-Javadoc)
       
   117 	 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
       
   118 	 */
       
   119 	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
       
   120 		
       
   121 		
       
   122 		//Storing parent for the current element
       
   123 		String parentElement = null;
       
   124 		try {
       
   125 			parentElement = elementStack.peek();
       
   126 		} catch (EmptyStackException e) {
       
   127 			// Ignoring this exception
       
   128 		}
       
   129 		// Parent element is stored => We can add current element to stack.
       
   130 		elementStack.push(localName);
       
   131 		
       
   132 		if(elemNameSet.contains(localName)){
       
   133 			
       
   134 			// Checking if possible parent element 
       
   135 			// restriction should be taken into account.
       
   136 			boolean parentElementCheckOk = true; // By default there is no restrictions
       
   137 			String parentRestriction = parentElementRestrictionMap.get(localName);
       
   138 			if(parentRestriction != null){
       
   139 								
       
   140 				if(parentElement == null || (! parentElement.equalsIgnoreCase(parentRestriction))){
       
   141 					// Parent restriction is required, and does not match
       
   142 					parentElementCheckOk = false;
       
   143 				}
       
   144 			}		
       
   145 			
       
   146 			if(parentElementCheckOk){
       
   147 				// This is an element we are interested in
       
   148 				isInsideAcceptedElement = true;
       
   149 				parsedElementName = localName;
       
   150 				
       
   151 				// Checking for possible attributes
       
   152 				Map<String, String> attrMap = attributeMap.get(localName);
       
   153 				if(attrMap != null && attrMap.size() > 0){
       
   154 
       
   155 					Set<String> attrSet = attrMap.keySet();			
       
   156 					for (int i = 0; i < attributes.getLength(); i++) {
       
   157 						String attrName = attributes.getLocalName(i);				
       
   158 						if(attrSet.contains(attrName)){
       
   159 							String attrValue = attributes.getValue(i);
       
   160 							parsedAttributeData.put(attrMap.get(attrName), attrValue);
       
   161 						}
       
   162 					}//for
       
   163 				}				
       
   164 			}			
       
   165 		}
       
   166 	}
       
   167 
       
   168 	/* (non-Javadoc)
       
   169 	 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
       
   170 	 */
       
   171 	public void characters(char[] ch, int start, int length) throws SAXException {
       
   172 		String characterDataString = new String(ch, start, length);
       
   173 
       
   174 		if(isInsideAcceptedElement){
       
   175 			if(parsedElementValue == null){
       
   176 				parsedElementValue = characterDataString;				
       
   177 			}
       
   178 			else{
       
   179 				parsedElementValue = parsedElementValue + characterDataString;								
       
   180 			}
       
   181 		}
       
   182 	}
       
   183 
       
   184 	/* (non-Javadoc)
       
   185 	 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
       
   186 	 */
       
   187 	public void endElement(String uri, String localName, String qName) throws SAXException {
       
   188 		
       
   189 		elementStack.pop(); // Updating element stack
       
   190 		
       
   191 		if(isInsideAcceptedElement){
       
   192 			// Adding element into parsed elements
       
   193 			if(parsedElementValue == null){
       
   194 				// If element did not contain value => using an empty string instead
       
   195 				parsedElementValue = ""; //$NON-NLS-1$
       
   196 			}
       
   197 			parsedElementsVector.add(new XMLElementData(parsedElementName, 
       
   198 					                 					parsedElementValue,
       
   199 					                 					parsedAttributeData));
       
   200 			isInsideAcceptedElement = false;
       
   201 			parsedElementName = null;
       
   202 			parsedElementValue = null;
       
   203 			// For the next element there is competely new data object reserved
       
   204 			parsedAttributeData = new LinkedHashMap<String, String>();
       
   205 		}
       
   206 	}
       
   207 
       
   208 	/* (non-Javadoc)
       
   209 	 * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
       
   210 	 */
       
   211 	public void error(SAXParseException e) throws SAXException {			
       
   212 		String xmlParseFailedUserMsg = Messages.getString("XMLDataSAXHandler.XML_Parse_Error_ConsoleMsg" //$NON-NLS-1$
       
   213 		                                                  + "( " + getCurrentParsePath() + ")");		 //$NON-NLS-1$ //$NON-NLS-2$
       
   214 		DbgUtility.println(DbgUtility.PRIORITY_OPERATION, 
       
   215 				xmlParseFailedUserMsg);
       
   216 		APIQueryConsole.getInstance().println(xmlParseFailedUserMsg + e.getMessage(), APIQueryConsole.MSG_ERROR);
       
   217 		throw new SAXException(e.getMessage());			
       
   218 	}
       
   219 
       
   220 	/* (non-Javadoc)
       
   221 	 * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
       
   222 	 */
       
   223 	public void fatalError(SAXParseException e) throws SAXException {
       
   224 		String xmlParseFailedUserMsg = Messages.getString("XMLDataSAXHandler.XML_Parse_FatalError_ConsoleMsg") //$NON-NLS-1$
       
   225 														  + "( " + getCurrentParsePath() + ")";  //$NON-NLS-1$ //$NON-NLS-2$
       
   226 		DbgUtility.println(DbgUtility.PRIORITY_OPERATION, 
       
   227 				xmlParseFailedUserMsg);
       
   228 		APIQueryConsole.getInstance().println(xmlParseFailedUserMsg + e.getMessage(), APIQueryConsole.MSG_ERROR);
       
   229 		throw new SAXException(e.getMessage());			
       
   230 	}
       
   231 
       
   232 	/* (non-Javadoc)
       
   233 	 * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
       
   234 	 */
       
   235 	public void warning(SAXParseException e) throws SAXException {
       
   236 		String xmlParseFailedUserMsg = Messages.getString("XMLDataSAXHandler.XML_Parse_Warning_ConsoleMsg" //$NON-NLS-1$ 
       
   237 				+ "( " + getCurrentParsePath() + ")");  //$NON-NLS-1$ //$NON-NLS-2$
       
   238 		DbgUtility.println(DbgUtility.PRIORITY_OPERATION, 
       
   239 				xmlParseFailedUserMsg);
       
   240 		APIQueryConsole.getInstance().println(xmlParseFailedUserMsg + e.getMessage(), APIQueryConsole.MSG_WARNING);
       
   241 	} 
       
   242 	
       
   243 	/**
       
   244 	 * Element data that was parsed.
       
   245 	 * @return Elements parsed.
       
   246 	 */
       
   247 	public XMLElementData[] getParsedElements(){
       
   248 		return parsedElementsVector.toArray(new XMLElementData[0]);
       
   249 	}
       
   250 
       
   251 	/**
       
   252 	 * Returns current parse path based on the information stored in the stack.
       
   253 	 */
       
   254 	private String getCurrentParsePath(){
       
   255 		StringBuffer path = new StringBuffer("/"); //$NON-NLS-1$
       
   256 		for (ListIterator<String> iter = elementStack.listIterator(); iter.hasNext();) {
       
   257 			String elemName = (String) iter.next();
       
   258 			path.append(elemName + "/");			 //$NON-NLS-1$
       
   259 		}
       
   260 		return path.toString();
       
   261 	}
       
   262 	
       
   263 }