blob: e2c7884923bc916e9151fc9c0d63d4b14a3a3a80 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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.motorola.studio.android.model.resources.parser;
import java.io.IOException;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.List;
import org.apache.xerces.parsers.DOMParser;
import org.eclipse.jface.text.IDocument;
import org.eclipse.osgi.util.NLS;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.motorola.studio.android.codeutils.i18n.CodeUtilsNLS;
import com.motorola.studio.android.common.exception.AndroidException;
import com.motorola.studio.android.common.log.StudioLogger;
import com.motorola.studio.android.model.resources.types.AbstractResourceNode;
import com.motorola.studio.android.model.resources.types.AbstractResourceNode.NodeType;
import com.motorola.studio.android.model.resources.types.AbstractSimpleNameResourceNode;
import com.motorola.studio.android.model.resources.types.ColorNode;
import com.motorola.studio.android.model.resources.types.DimenNode;
import com.motorola.studio.android.model.resources.types.DrawableNode;
import com.motorola.studio.android.model.resources.types.IResourceTypesAttributes;
import com.motorola.studio.android.model.resources.types.ResourcesNode;
import com.motorola.studio.android.model.resources.types.StringNode;
import com.motorola.studio.android.model.resources.types.UnknownNode;
/**
* Abstract class that implements methods to parse a resource file
*/
public class AbstractResourceFileParser implements IResourceTypesAttributes
{
/**
* The root nodes of the resource file
*/
protected final List<AbstractResourceNode> rootNodes;
/**
* Default constructor
*/
public AbstractResourceFileParser()
{
rootNodes = new LinkedList<AbstractResourceNode>();
}
/**
* Parses an IDocument object containing a resource file content
*
* @param document the IDocument object
* @param sourceFileName The resource file that is being parsed
*
* @throws SAXException When a parsing error occurs
* @throws IOException When a reading error occurs
*/
public void parseDocument(IDocument document, String sourceFileName) throws AndroidException
{
Element element;
DOMParser domParser = new DOMParser();
rootNodes.clear();
StringReader stringReader = null;
try
{
stringReader = new StringReader(document.get());
domParser.parse(new InputSource(stringReader));
}
catch (SAXException e)
{
String errMsg =
NLS.bind(CodeUtilsNLS.EXC_AbstractResourceFileParser_ErrorParsingTheXMLFile,
sourceFileName, e.getLocalizedMessage());
StudioLogger.error(AbstractResourceFileParser.class, errMsg, e);
throw new AndroidException(errMsg);
}
catch (IOException e)
{
String errMsg =
NLS.bind(CodeUtilsNLS.EXC_AbstractResourceFileParser_ErrorReadingTheXMLContent,
sourceFileName, e.getLocalizedMessage());
StudioLogger.error(AbstractResourceFileParser.class, errMsg, e);
throw new AndroidException(errMsg);
}
finally
{
if (stringReader != null)
{
stringReader.close();
}
}
element = domParser.getDocument().getDocumentElement();
parseNode(element, null);
}
/**
* Parses a XML Node
*
* @param element The XML Node
* @param rootNode The XML Node parent (An AbstractResourceNode that has been parsed)
*/
private void parseNode(Node node, AbstractResourceNode rootNode)
{
if (node instanceof Element)
{
Element element = (Element) node;
AbstractResourceNode arNode;
Node xmlNode;
NodeList xmlChildNodes;
NamedNodeMap attributes = element.getAttributes();
NodeType nodeType = identifyNode(element);
switch (nodeType)
{
case Resources:
arNode = parseResourcesNode();
break;
case String:
arNode = parseStringNode(attributes);
break;
case Color:
arNode = parseColorNode(attributes);
break;
case Dimen:
arNode = parseDimenNode(attributes);
break;
case Drawable:
arNode = parseDrawableNode(attributes);
break;
default:
arNode = parseUnknownNode(node);
}
// Adds the child nodes
xmlChildNodes = element.getChildNodes();
for (int i = 0; i < xmlChildNodes.getLength(); i++)
{
xmlNode = xmlChildNodes.item(i);
parseNode(xmlNode, arNode);
}
if (rootNode == null)
{
rootNodes.add(arNode);
}
else
{
rootNode.addChildNode(arNode);
}
}
else if ((node instanceof Text) && (rootNode != null))
{
if ((node.getNodeValue() != null) && (node.getNodeValue().trim().length() > 0))
{
if (rootNode instanceof AbstractSimpleNameResourceNode)
{
AbstractSimpleNameResourceNode asnrNode =
(AbstractSimpleNameResourceNode) rootNode;
if (asnrNode.getNodeValue() == null)
{
asnrNode.setNodeValue(node.getNodeValue());
}
}
else
{
UnknownNode unknownNode = (UnknownNode) rootNode;
if (unknownNode.getNodeValue() == null)
{
unknownNode.setNodeValue(node.getNodeValue());
}
}
}
}
}
/**
* Identifies an XML Node type as an AbstractResourceNode type.
*
* @param xmlNode The XML Node
* @return The corresponding AndroidManifestNode type to the XML Node
*/
private NodeType identifyNode(Element xmlNode)
{
String nodeName = xmlNode.getNodeName();
NodeType identifiedType = AbstractResourceNode.getNodeType(nodeName);
return identifiedType;
}
/**
* Parses a <resources> node
*
* @return An AbstractResourceNode object that represents the <resources> node
*/
private AbstractResourceNode parseResourcesNode()
{
return new ResourcesNode();
}
/**
* Parses a <string> node
*
* @param attributes the node attributes list
* @return An AbstractResourceNode object that represents the <string> node
*/
private AbstractResourceNode parseStringNode(NamedNodeMap attributes)
{
StringNode arNode = new StringNode("");
Node attribute;
String attrName, attrValue;
for (int i = 0; i < attributes.getLength(); i++)
{
attribute = attributes.item(i);
attrName = attribute.getNodeName();
attrValue = attribute.getNodeValue();
if (attrName.equalsIgnoreCase(ATTR_NAME))
{
arNode.setName(attrValue);
}
else
{
arNode.addUnknownAttribute(attrName, attrValue);
}
}
return arNode;
}
/**
* Parses a <color> node
*
* @param attributes the node attributes list
* @return An AbstractResourceNode object that represents the <color> node
*/
private AbstractResourceNode parseColorNode(NamedNodeMap attributes)
{
ColorNode arNode = new ColorNode("");
Node attribute;
String attrName, attrValue;
for (int i = 0; i < attributes.getLength(); i++)
{
attribute = attributes.item(i);
attrName = attribute.getNodeName();
attrValue = attribute.getNodeValue();
if (attrName.equalsIgnoreCase(ATTR_NAME))
{
arNode.setName(attrValue);
}
else
{
arNode.addUnknownAttribute(attrName, attrValue);
}
}
return arNode;
}
/**
* Parses a <dimen> node
*
* @param attributes the node attributes list
* @return An AbstractResourceNode object that represents the <diment> node
*/
private AbstractResourceNode parseDimenNode(NamedNodeMap attributes)
{
DimenNode arNode = new DimenNode("");
Node attribute;
String attrName, attrValue;
for (int i = 0; i < attributes.getLength(); i++)
{
attribute = attributes.item(i);
attrName = attribute.getNodeName();
attrValue = attribute.getNodeValue();
if (attrName.equalsIgnoreCase(ATTR_NAME))
{
arNode.setName(attrValue);
}
else
{
arNode.addUnknownAttribute(attrName, attrValue);
}
}
return arNode;
}
/**
* Parses a <drawable> node
*
* @param attributes the node attributes list
* @return An AbstractResourceNode object that represents the <drawable> node
*/
private AbstractResourceNode parseDrawableNode(NamedNodeMap attributes)
{
DrawableNode arNode = new DrawableNode("");
Node attribute;
String attrName, attrValue;
for (int i = 0; i < attributes.getLength(); i++)
{
attribute = attributes.item(i);
attrName = attribute.getNodeName();
attrValue = attribute.getNodeValue();
if (attrName.equalsIgnoreCase(ATTR_NAME))
{
arNode.setName(attrValue);
}
else
{
arNode.addUnknownAttribute(attrName, attrValue);
}
}
return arNode;
}
/**
* Parses an unknown node
*
* @param node The xml node
* @return An AbstractResourceNode object that represents the unknown node
*/
private AbstractResourceNode parseUnknownNode(Node node)
{
UnknownNode arNode = new UnknownNode(node.getNodeName());
NamedNodeMap attributes = node.getAttributes();
Node attribute;
String attrName, attrValue;
for (int i = 0; i < attributes.getLength(); i++)
{
attribute = attributes.item(i);
attrName = attribute.getNodeName();
attrValue = attribute.getNodeValue();
arNode.addUnknownAttribute(attrName, attrValue);
}
return arNode;
}
}