2010-12-31 13 views
19

Robię projekt parsowania niektórych danych z pliku XML.Parser JAVA SAX dzieli rozmowy na znaki()

Na przykład, XML jest

<abc>abcdefghijklmno</abc> 

muszę analizować "abcdefghijkmnlp".

Ale jednocześnie przetestować parse, odkrywam wielki problem:

public class parser{ 
    private boolean hasABC = false; 


     //Constructor HERE 
     ...................... 
     ...................... 

    @Override 
    public void startDocument() throws SAXException{ 
    } 

    @Override 
    public void endDocument() throws SAXException{ 
    } 

    @Override 
    public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException{ 
      if ("abc".equalsIgnoreCase(localName)) { 
       this.hasABC = true; 
      } 
     } 
     @Override 
     public void endElement(String namespaceURI, String localName, String qName) throws SAXException{ 
      if ("abc".equalsIgnoreCase(localName)) { 
       this.hasABC = false; 
      } 
     } 
     @Override 
     public void characters(char ch[], int start, int length){ 
      String content = new String(ch, start, length).trim(); 
      if(this.hasABC){ 
       System.out.println("ABC = " + content); 
      } 
     } 
    } 

I okazuje się, że parser jest analizowany tag dwa raz Print System OUT,

ABC = abcdefghi

ABC = jklmno < < ============ podzielić wiadomość

Dlaczego auto parser oddzwonić znaki() dwa razy ????

Czy XML ma jakieś "\ n" lub "\ r" ???

+0

Witam @Rebecca, znalazłeś rozwiązanie dla tego problemu, mam do czynienia z tym samym problemem. – Ramesh

Odpowiedz

32

Analizator wywołuje metodę characters więcej niż jeden raz, ponieważ może i zezwala na specyfikację. Pomaga to w szybkim analizowaniu składni i niskim poziomie pamięci. Jeśli chcesz, aby pojedynczy ciąg znaków tworzył nowy obiekt StringBuilder w metodzie startElement i przetwarzaj go w metodzie endElement.

+0

Tak, używam zmiennej gobal do przechowywania tekstu w charaters() i wypisywania tej zmiennej w endElement(). – rebecca

+0

@rebecca fragment kodu z pytaniem nie robi tego, zakładam, że odnosisz się teraz do jakiegoś ostatnio poprawionego kodu? :) – rogerdpack

7

Będziesz zaskoczony, ale jest to udokumentowane zachowanie, tzn. Nie można założyć, że analizator składni odczyta i zwróci wszystkie dane tekstowe elementu w jednym wywołaniu zwrotnym. Miałem takie samo doświadczenie wcześniej. Aby obsłużyć tę sytuację, musisz wpisać kod lub przełączyć się na Stax parser. Możesz użyć CharArrayWriter, aby gromadzić dane w wielu wywołaniach zwrotnych.

Patrz niżej od JavaDoc of ContentHandler.characters(...)

parser wywoła tę metodę do raportu każda porcja danych znakowych. Analizatory składni SAX mogą zwracać wszystkie sąsiadujące dane znaków w jednym kawałku, lub one mogą podzielić na kilka porcji; Jednak wszystkie znaki w każdym pojedynczym zdarzeniu muszą pochodzić z tego samego obiektu zewnętrznego, co , dzięki czemu lokalizator dostarczy użytecznych informacji.

+0

Naprawdę szkoda, że ​​nie było flagi na * nie * zrób to: | – rogerdpack

3

To jest funkcja SAX. Analizator składni może dzielić segmenty tekstu i wywoływać metodę characters tyle razy, ile się podoba.

Powodem tego jest wydajność, która według SAX ma wyższy priorytet niż łatwość użytkowania. SAX mógł wykorzystać swój wewnętrzny bufor, więc aby uniknąć kopiowania, przekazuje dane, które dotychczas zawierał do twojego kodu.

4

można zmienić początek, koniec i sposobu znaków takich jak:

  • dodać "globalne" zawartość zmiennej
  • następnie wartość null go w metodzie start (zawartość == null)
  • w metodzie końcowego u można println lub dodać ten ciąg zawartości do jakiegoś przedmiotu
  • w metodzie znaków u można zrobić jeśli/else:

    if (content == null) 
    { 
        content = new String(ch, start, length); 
    } else { 
        content += new String(ch, start, length); 
    } 
    

    Brutalny sposób (lepiej zrobić to z konstruktorem), ale działa i "ciąg" nie jest już podzielony.