Reputation: 1230
The concept of my program is to parse an XML file that can describe a set of classes within an XML stream. Each class can obviously have several methods and several properties. The methods in turn can also have several parameters.
Below is an example of the XML file:
<stream>
<class package="Mainpack" name="Person" visibility="public" alias="Aaron" type="class" spot="C">
<property name="id" type="String" visibility="public"></property>
<property name="name" type="String" visibility="public"></property>
<method name="setID" return="void" visibility="public">
<parameter name="name" type="string"> </parameter>
</method>
<method name="getID" return="String" visibility="public"></method>
</class>
</stream>
Each element (stream, class etc...) has a class that describes it with getters, setters and an empty constructor. The stream contains a list of classes. Classes contain attributes for name, package etc... and lists for methods and parameters (which are separate classes on their own). I will not include these because I think they are straightforward.
This is the XMLHandler class that I have written:
public class XMLHandler extends DefaultHandler {
Boolean currentElement = false;
String currentValue = null;
public static XMLStream xmlStream;
public XMLClass xmlClass = null;
public XMLMethod xmlMethod = null;
public XMLProperty xmlProperty = null;
public XMLParameter xmlParameter = null;
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
currentElement = true;
switch (localName) {
case "stream":
{
xmlStream = new XMLStream();
}
case "class":
{
/** Start and get attribute values */
xmlClass = new XMLClass();
String attr = attributes.getValue("package");
xmlClass.setPackageName(attr);
attr = attributes.getValue("name");
xmlClass.setClassName(attr);
attr = attributes.getValue("visibility");
xmlClass.setVisibility(attr);
attr = attributes.getValue("alias");
xmlClass.setAlias(attr);
attr = attributes.getValue("type");
xmlClass.setType(attr);
attr = attributes.getValue("spot");
xmlClass.setSpot(attr.charAt(0));
break;
}
case "method":
{
xmlMethod = new XMLMethod();
String attr = attributes.getValue("name");
xmlMethod.setName(attr);
attr = attributes.getValue("return");
xmlMethod.setReturnType(attr);
attr = attributes.getValue("visibility");
xmlMethod.setVisibility(attr);
xmlClass.addMethod(xmlMethod);
break;
}
case "property":
{
xmlProperty = new XMLProperty();
String attr = attributes.getValue("name");
xmlProperty.setName(attr);
attr = attributes.getValue("type");
xmlProperty.setType(attr);
attr = attributes.getValue("visibility");
xmlProperty.setVisibility(attr);
xmlClass.addProperty(xmlProperty);
break;
}
case "parameter":
{
xmlParameter = new XMLParameter();
String attr = attributes.getValue("name");
xmlParameter.setName(attr);
attr = attributes.getValue("type");
xmlParameter.setType(attr);
xmlMethod.addParameter(xmlParameter);
break;
}
}
}
/** Called when tag closing ( ex:- <name>AndroidPeople</name>
* -- </name> )*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
currentElement = false;
if (localName.equalsIgnoreCase("class"))
xmlStream.addClass(xmlClass);
else if (localName.equalsIgnoreCase("method"))
xmlClass.addMethod(xmlMethod);
else if (localName.equalsIgnoreCase("property"))
xmlClass.addProperty(xmlProperty);
else if (localName.equalsIgnoreCase("parameter"))
xmlMethod.addParameter(xmlParameter);
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (currentElement) {
currentValue = new String(ch, start, length);
currentElement = false;
}
}
}
I hope the logic is correct. The parser creates an instance of Stream when it meets the stream tag and sets the attributes. When meeting a class tag, it does the same. On the closing tag for class, the class instance is added to the stream's list of classes. This behavior is repeated with regards to methods and properties in relation to classes, and parameters in relation to methods.
I am testing the parser in a windows application, but you can using this method:
public static void main(String[]args)
{
try {
String xmlst = "<stream>\n<class package=\"Mainpack\" name=\"Person\" "
+ "visibility=\"public\" alias=\"Aaron\" type=\"class\" spot=\"C\">\n "
+ " <property name=\"id\" type=\"String\" visibility=\"public\"></property>\n "
+ " <method name=\"getID\" return=\"void\" visibility=\"public\">\n\t<parameter name=\"name\" type=\"string\">"
+ " </parameter>\n </method>\n</class>\n</stream>";
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
XMLHandler xh = new XMLHandler();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlst));
xr.setContentHandler(xh);
xr.parse(new InputSource(is.getByteStream()));
XMLStream xmlStream = XMLHandler.xmlStream;
for (int i=0; i<xmlStream.getClasses().size(); i++)
{
System.out.println("*** CLASS ***");
System.out.println(xmlStream.getClasses().get(i).getClassName());
System.out.println(xmlStream.getClasses().get(i).getType());
for (int j=0; j<xmlStream.getClasses().get(i).getProperties().size(); j++)
{
System.out.println("*** PROP ***");
System.out.println(xmlStream.getClasses().get(i).getProperties().get(j).getName());
System.out.println(xmlStream.getClasses().get(i).getProperties().get(j).getType());
}
for (int j=0; j<xmlStream.getClasses().get(i).getMethods().size(); j++)
{
System.out.println("*** METH ***");
System.out.println(xmlStream.getClasses().get(i).getMethods().get(j).getName());
System.out.println(xmlStream.getClasses().get(i).getMethods().get(j).getReturnType());
for (int k=0; k<xmlStream.getClasses().get(i).getMethods().get(j).getParameters().size(); k++)
{
System.out.println("*** PARAMS ***");
System.out.println(xmlStream.getClasses().get(i).getMethods().get(j).getParameters().get(k).getName());
System.out.println(xmlStream.getClasses().get(i).getMethods().get(j).getParameters().get(k).getType());
}
}
}
} catch (IOException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
} catch (ParserConfigurationException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
} catch (SAXException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
The program is encountering an MalformedURLException when running the line: "xr.parse(new inputSource(is.getByteStream()));"
Does anyone have any ideas to what's wrong?
Upvotes: 1
Views: 2679
Reputation: 8229
Save your xml document as .xml
document (nuff said) and try this approach to run your parser:
XMLReader reader = XMLReaderFactory.createXMLReader();
XMLHandler xh = new XMLHandler();
reader.setContentHandler(xh);
reader.parse(PATH_TO_FILE);
instead of your code:
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
XMLHandler xh = new XMLHandler();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlst));
xr.setContentHandler(xh);
xr.parse(new InputSource(is.getByteStream()));
Hope it helps.
Upvotes: 2