2010-09-29 28 views
5

Muszę parsować strukturę XML w języku JAVA przy użyciu analizatora składni SAX.Parsowanie struktury XML z nieznaną ilością rekursji przy użyciu SAX

Problem polega na tym, że struktura jest rekursywna z nieokreśloną liczbą rekursji. To nadal nie jest takie ważne, ale najważniejsze, że nie mogę wykorzystać funkcjonalności przestrzeni nazw XML, a tagi są takie same na każdym poziomie rekursji.

Oto przykład struktury.

<?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> 

Jak widać, istnieje rekursja, lepiej nieokreślona liczba rekurencji. Teraz mój problem polega na tym, jak wyodrębnić wszystkie dane dla każdej rekursji i zapisać je na przykład w HashMap.

mogę zdefiniować ContentHandler dla zaistnienia Tags i go rozpakować zawartość w HashMap i umieścić go z powrotem w mistrzaHashMap zdefiniowanej w głównym obsługi zawartości, ale nie jestem pewien gorący, aby to zrobić.

Jak wyodrębnić i zapisać zawartość rekurencyjnej struktury XML bez używania przestrzeni nazw?

+0

Do czego potrzebne są klucze w HashMap? wartość atrybutu? – LarsH

+0

Tak, klucze będą wartościami atrybutów. –

Odpowiedz

3

Zapoznaj się z this set of Javaworld articles on using SAX. Pokazuje prostą metodę analizy rekurencyjnej struktury XML za pomocą SAX. Tworzy automat stanów pokazujący dla każdego elementu, jakie elementy może on zawierać. Gdy twój contentHandler przechodzi przez xml, utrzymuje stos pokazujący, który element jest aktualnie włączony.

+0

Wielkie dzięki. To jest dokładnie to, czego szukałem. –

+0

+1 Ten link był szczególnie pomocny. –

0

Jeśli chcesz parsować XML w rekursywnie, musisz użyć opcji Stos i sprawdzić głębokość w strukturze XML. Dla mojego struktury XML w tym formacie (maks. Głębokość 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> 

użyłem tego Pseudokod Java i działa całkiem dobrze w moim Android app (dla znanej głębokości). Jeśli nie znasz liczby rekurencji i nie znasz głębi, możesz po prostu edytować mój kod i zamiast 3 obiektów ArrayList (i 3 obiektów kategorii) możesz użyć jednej kolekcji dynamicznej (na przykład ArrayList<ArrayList<Category>>) i wstaw ArrayList<Category> do indeksu ArrayList<ArrayList<Category>>, który prezentuje metodę 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(); 
    } 
}