Если вы хотите рекурсивно анализировать XML с помощью SAX, вы должны использовать Stack и проверить глубину структуры XML. Для моей структуры XML в этом формате (максимальная глубина 3):
<Response action='categories'>
<Categories>
<Category name='{name}' id='{id}' numSubcategories='{num}'>
<Category name='{name}' id='{id}' numSubcategories='{num}'>
<Category name='{name}' id='{id}' numSubcategories='0'/>
...
</Category>
...
</Category>
...
</Categories>
</Response>
Я использовал этот псевдокод Java, и он прекрасно работает в моем приложении для Android (для известной глубины). Если вы не знаете количество рекурсий и не знаете глубину, вы можете просто отредактировать мой код и вместо 3-х объектов ArrayList (и 3-х объектов Category) вы можете использовать одну динамическую коллекцию (например, ArrayList<ArrayList<Category>>
) и поместите ArrayList<Category>
в ArrayList<ArrayList<Category>>
, используя индекс, который представляет getDepth()
метод.
public class CategoriesResponse extends Response
{
private Stack<String> mTagStack = new Stack<String>();
private ArrayList<Category> mCategories1;
private ArrayList<Category> mCategories2;
private ArrayList<Category> mCategories3;
Category mCategory1;
Category mCategory2;
Category mCategory3;
private int mCurrentDepth = 0;
public ArrayList<Category> getCategories()
{
return mCategories1;
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
super.startElement(uri, localName, qName, attributes);
...
if(localName.equals("Category"))
{
// push element into the stack
mTagStack.push(localName);
// get data
int id = Integer.parseInt(attributes.getValue("id"));
String name = attributes.getValue("name");
int numSubcategories = Integer.parseInt(attributes.getValue("numSubcategories"));
// create new Category
if(getDepth()==1)
{
mCategory1 = new Category(id, name);
mCategory1.setSubcategoriesSize(numSubcategories);
mCategory1.setSubcategories(null);
if(mCurrentDepth<getDepth()) mCategories1 = new ArrayList<Category>(); // deeping down so create new list
}
else if(getDepth()==2)
{
mCategory2 = new Category(id, name);
mCategory2.setSubcategoriesSize(numSubcategories);
mCategory2.setSubcategories(null);
if(mCurrentDepth<getDepth()) mCategories2 = new ArrayList<Category>(); // deeping down so create new list
}
else if(getDepth()==3)
{
mCategory3 = new Category(id, name);
mCategory3.setSubcategoriesSize(numSubcategories);
mCategory3.setSubcategories(null);
if(mCurrentDepth<getDepth()) mCategories3 = new ArrayList<Category>(); // deeping down so create new list
}
// debug output
if(mCurrentDepth<getDepth()) Log.d("SAX_TEST", getPath() + " | " + getDepth() + " | DEEPING DOWN");
else if(mCurrentDepth>getDepth()) Log.d("SAX_TEST", getPath() + " | " + getDepth() + " | DEEPING UP");
else if(mCurrentDepth==getDepth()) Log.d("SAX_TEST", getPath() + " | " + getDepth() + " | STAYING");
// set current depth
mCurrentDepth = getDepth();
return;
}
}
public void characters(char[] ch, int start, int length) throws SAXException
{
super.characters(ch, start, length);
...
}
public void endElement(String uri, String localName, String qName) throws SAXException
{
super.endElement(uri, localName, qName);
...
if(localName.equals("Category"))
{
// debug output
Log.d("SAX_TEST", "END OF THE ELEMENT IN DEPTH " + getDepth() + " | " + mCurrentDepth);
// deeping up so set sublist for current category
if(getDepth()!=mCurrentDepth)
{
if(getDepth()==2) mCategory2.setSubcategories(mCategories3);
if(getDepth()==1) mCategory1.setSubcategories(mCategories2);
}
// add current category to list
if(getDepth()==1)
{
mCategories1.add(mCategory1);
}
else if(getDepth()==2)
{
mCategories2.add(mCategory2);
}
else if(getDepth()==3)
{
mCategories3.add(mCategory3);
}
// pop element from stack
mTagStack.pop();
return;
}
}
// debug output - write current path
private String getPath()
{
String buffer = "";
Enumeration<String> e = mTagStack.elements();
while (e.hasMoreElements())
{
buffer = buffer + "/" + (String) e.nextElement();
}
return buffer;
}
// get current depth of stack
private int getDepth()
{
return mTagStack.size();
}
}