使用SAX解析具有未知递归量的XML结构

时间:2010-09-29 14:36:06

标签: java xml parsing recursion sax

我必须使用SAX解析器解析JAVA中的XML结构。

问题是结构是递归的,具有未指定的递归计数。这仍然不是什么大问题,最重要的是我无法利用XML命名空间功能,并且每个递归级别的标签都是相同的。

以下是结构示例。

<?xml version="1.0" encoding="UTF-8"?>
<RootTag>
    <!-- LOADS OF OTHER TAGS -->
    <Tags attribute="value">
        <Tag attribute="value">
            <SomeOtherTag></SomeOtherTag>
            <Tags attribute="value">
                <Tag attribute="value">
                    <SomeOtherTag></SomeOtherTag>
                    <Tags attribute="value">
                        <!-- MORE OF THE SAME STRUCTURE -->
                    </Tags>
                </Tag>
            </Tags>
        </Tag>
    </Tags>
    <!-- LOADS OF OTHER TAGS -->
</RootTag>

正如您所看到的那样,有一个递归,更好的是一个未定义的递归数。现在我的问题是如何为每次递归提取所有数据,并将其保存在HashMap中。

我可以为ContentHandler的出现定义一个Tags,并让它在HashMap中提取内容并将其放回 master {{ 1}}在主要内容处理程序中定义,但我不确定要做到这一点。

如何在不使用命名空间的情况下提取和保存递归XML结构的内容?

2 个答案:

答案 0 :(得分:3)

结帐this set of Javaworld articles on using SAX。它演示了使用SAX解析递归XML结构的简单方法。它创建一个状态机,为每个元素显示它可以包含哪些元素。当你的contentHandler遍历xml时,它会保持一个堆栈,显示它当前所在的元素。

答案 1 :(得分:0)

如果要通过SAX递归解析XML,则必须使用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();
    }
}