Разбор XML-структуры с неизвестным количеством рекурсий с использованием SAX - PullRequest
6 голосов
/ 29 сентября 2010

Я должен проанализировать XML-структуру в JAVA, используя SAX-анализатор.

Проблема в том, что структура является рекурсивной с неопределенным количеством рекурсий. Это все еще не такая уж большая проблема, большая проблема в том, что я не могу воспользоваться функциональностью пространства имен 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 HashMap, определенный в основном обработчике содержимого но я не уверен, что могу это сделать.

Как извлечь и сохранить содержимое рекурсивной структуры XML без использования пространств имен?

Ответы [ 2 ]

3 голосов
/ 29 сентября 2010

Проверьте этот набор статей Javaworld по использованию SAX .Он демонстрирует простой способ анализа рекурсивной XML-структуры с использованием SAX.Он создает конечный автомат, показывающий для каждого элемента, какие элементы он может содержать.Когда ваш contentHandler обходит xml, он сохраняет стек, показывающий, к какому элементу он подключен.

0 голосов
/ 14 февраля 2012

Если вы хотите рекурсивно анализировать 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();
    }
}
...