2011-08-26 10 views
5

¿Es posible dar expresiones de ruta en el analizador SAX? Tengo un archivo XML que tiene algunas etiquetas con el mismo nombre, pero están en un elemento diferente. ¿Hay alguna forma de diferenciar entre ellos? Aquí es el XML:usando el analizador SAX, ¿cómo se analiza un archivo xml que tiene las mismas etiquetas pero en diferentes elementos?

<Schools> 
    <School> 
     <ID>335823</ID> 
     <Name>Fairfax High School</Name> 
     <Student> 
      <ID>4195653</ID> 
      <Name>Will Turner</Name> 
     </Student> 
     <Student> 
      <ID>4195654</ID> 
      <Name>Bruce Paltrow</Name> 
     </Student> 
     <Student> 
      <ID>4195655</ID> 
      <Name>Santosh Gowswami</Name> 
     </Student> 
    </School> 
    <School> 
     <ID>335824</ID> 
     <Name>FallsChurch High School</Name> 
     <Student> 
      <ID>4153</ID> 
      <Name>John Singer</Name> 
     </Student> 
     <Student> 
      <ID>4154</ID> 
      <Name>Shane Warne</Name> 
     </Student> 
     <Student> 
      <ID>4155</ID> 
      <Name>Eddie Diaz</Name> 
     </Student> 
    </School> 
</Schools> 

quiero diferenciar entre el nombre y la identificación de un estudiante del nombre y la identificación de una escuela.

Gracias por la respuesta:

he creado un POJO estudiante que tiene la siguiente campos- school_id, school_name, student_id y métodos student_name y get y set para ellos. Esta es mi implementación de analizador temporal. Cuando analizo el xml, necesito poner los valores de nombre de la escuela, identificación, nombre del estudiante, identificación en el pojo y devolverlo. ¿Puede decirme cómo debería implementar la pila para la diferenciación? Esta es mi estructura de analizador ::

import org.xml.sax.Attributes; 
import org.xml.sax.SAXException; 
import org.xml.sax.helpers.DefaultHandler; 

public class HandleXML extends DefaultHandler { 

    private student info; 
    private boolean school_id = false; 
    private boolean school_name = false; 
    private boolean student_id = false; 
    private boolean student_name = false; 
    private boolean student = false; 
    private boolean school = false; 


    public HandleXML(student record) { 
     super(); 
     this.info = record; 
     school_id = false; 
     school_name = false; 
     student_id = false; 
     student_name = false; 
     student = false; 
     school = false; 
    } 

    @Override 
    public void startElement(String uri, String localName, 
      String qName, Attributes attributes) 
      throws SAXException { 
    if (qName.equalsIgnoreCase("student")) { 
      student = true; 
     } 
    if (qName.equalsIgnoreCase("school")) { 
      school_id = true; 
     } 
    if (qName.equalsIgnoreCase("school_id")) { 
      school_id = true; 
     } 
    if (qName.equalsIgnoreCase("student_id")) { 
      student_id = true; 
     } 
    if (qName.equalsIgnoreCase("school_name")) { 
      school_name = true; 
     } 
    if (qName.equalsIgnoreCase("student_name")) { 
      student_name = true; 
     } 
    } 

    @Override 
    public void endElement(String uri, String localName, 
      String qName) 
      throws SAXException { 
    } 

    @Override 
    public void characters(char ch[], int start, int length) 
      throws SAXException { 

     String data = new String(ch, start, length); 

    } 
} 
+0

También puedes ver: http://stackoverflow.com/questions/1863250/ - Hay algunos proyectos que le permiten utilizar un subconjunto de XPath con un documento de streaming. Si puede adaptar su problema a ese subconjunto, el código resultante sería ampliamente preferible a cualquier código de controlador SAX enrollado a mano. –

+0

El análisis SAX con contexto es como una máquina de estado: https://en.wikipedia.org/wiki/Finite-state_machine, necesita tener algunos indicadores que puede activar/desactivar para saber dónde se encuentra, pero puede hacerlo rápidamente. se vuelven muy desordenados y debes considerar alternativas antes de ir demasiado lejos. –

Respuesta

13

Bueno, no he jugado en años con SAX en Java, por lo que aquí es mi opinión sobre ella:

package play.xml.sax; 

import org.xml.sax.Attributes; 
import org.xml.sax.SAXException; 
import org.xml.sax.helpers.DefaultHandler; 

import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.parsers.SAXParser; 
import javax.xml.parsers.SAXParserFactory; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Stack; 

public class Test1 { 
    public static void main(String[] args) { 
     SAXParserFactory spf = SAXParserFactory.newInstance(); 
     SchoolsHandler handler = new SchoolsHandler(); 
     try { 
      SAXParser sp = spf.newSAXParser(); 
      sp.parse("schools.xml", handler); 
      System.out.println("Number of read schools: " + handler.getSchools().size()); 
     } catch (SAXException se) { 
      se.printStackTrace(); 
     } catch (ParserConfigurationException pce) { 
      pce.printStackTrace(); 
     } catch (IOException ie) { 
      ie.printStackTrace(); 
     } 
    } 
} 

class SchoolsHandler extends DefaultHandler { 
    private static final String TAG_SCHOOLS = "Schools"; 
    private static final String TAG_SCHOOL = "School"; 
    private static final String TAG_STUDENT = "Student"; 
    private static final String TAG_ID = "ID"; 
    private static final String TAG_NAME = "Name"; 

    private final Stack<String> tagsStack = new Stack<String>(); 
    private final StringBuilder tempVal = new StringBuilder(); 

    private List<School> schools; 
    private School school; 
    private Student student; 

    public void startElement(String uri, String localName, String qName, Attributes attributes) { 
     pushTag(qName); 
     tempVal.setLength(0); 
     if (TAG_SCHOOLS.equalsIgnoreCase(qName)) { 
      schools = new ArrayList<School>(); 
     } else if (TAG_SCHOOL.equalsIgnoreCase(qName)) { 
      school = new School(); 
     } else if (TAG_STUDENT.equalsIgnoreCase(qName)) { 
      student = new Student(); 
     } 
    } 

    public void characters(char ch[], int start, int length) { 
     tempVal.append(ch, start, length); 
    } 

    public void endElement(String uri, String localName, String qName) { 
     String tag = peekTag(); 
     if (!qName.equals(tag)) { 
      throw new InternalError(); 
     } 

     popTag(); 
     String parentTag = peekTag(); 

     if (TAG_ID.equalsIgnoreCase(tag)) { 
      int id = Integer.valueOf(tempVal.toString().trim()); 
      if (TAG_STUDENT.equalsIgnoreCase(parentTag)) { 
       student.setId(id); 
      } else if (TAG_SCHOOL.equalsIgnoreCase(parentTag)) { 
       school.setId(id); 
      } 
     } else if (TAG_NAME.equalsIgnoreCase(tag)) { 
      String name = tempVal.toString().trim(); 
      if (TAG_STUDENT.equalsIgnoreCase(parentTag)) { 
       student.setName(name); 
      } else if (TAG_SCHOOL.equalsIgnoreCase(parentTag)) { 
       school.setName(name); 
      } 
     } else if (TAG_STUDENT.equalsIgnoreCase(tag)) { 
      school.addStudent(student); 
     } else if (TAG_SCHOOL.equalsIgnoreCase(tag)) { 
      schools.add(school); 
     } 
    } 

    public void startDocument() { 
     pushTag(""); 
    } 

    public List<School> getSchools() { 
     return schools; 
    } 

    private void pushTag(String tag) { 
     tagsStack.push(tag); 
    } 

    private String popTag() { 
     return tagsStack.pop(); 
    } 

    private String peekTag() { 
     return tagsStack.peek(); 
    } 
} 

class School { 
    private int id; 
    private String name; 
    private List<Student> students = new ArrayList<Student>(); 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public void addStudent(Student student) { 
     students.add(student); 
    } 

    public List<Student> getStudents() { 
     return students; 
    } 
} 

class Student { 
    private int id; 
    private String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 
} 

schools.xml contiene el XML de ejemplo. Tenga en cuenta que metí todo en un solo archivo, pero esto es solo porque estaba jugando.

+0

http://www.javatpoint.com/questionanswer.jsp?thread=3474 – Rohit

13

En un analizador SAX se le da a cada elemento en orden de documento. Debes mantener una pila para rastrear el anidamiento (empujar hacia la pila cuando manejas startElement, y pop para endElement). Puede diferenciar los diferentes elementos <Name> por lo que hay actualmente en la pila.

O bien, mantenga una variable que indique si ha encontrado una etiqueta <School> o <Student> para indicarle qué tipo de <Name> está viendo.

+4

+1 para mantener una pila, ese es el camino a seguir. puede generar una cadena similar a Xpath imprimiendo el contenido actual de la pila.Usar banderas para decir en qué etiqueta estás dentro es simplemente feo. :-P –

2

Sí, entender xml usando un analizador SAX generalmente es un poco más complicado que trabajar con DOM. básicamente, necesitas mantener el estado/contexto en tu analizador SAX para que puedas diferenciar entre esas situaciones.

nota, la otra clave para implementar un controlador SAX es comprender que los valores pueden dividirse en múltiples eventos de caracteres.

1

Sax se basa en eventos, a través de devoluciones de llamada puede leer el documento XML en serie. Sax es bueno para leer documentos XML grandes ya que el documento completo no se carga en la memoria. Es posible que desee consultar Xpath, p.

XPathFactory xPathFactory = XPathFactory.newInstance(); 
XPath xPath = xPathFactory.newXPath(); 
String expression = "/Schools/school/ ..."; 
XPathExpression xPathExpression = xPath.compile(expression); 
// Compile the expression to get a XPathExpression object. 
Object result = xPathExpression.evaluate(xmlDocument); 
+0

Es posible en SAX, como se explica muy bien en la respuesta de Jim Garrison. –

+1

@Don Roby, la corrección es posible, pero ¿realmente lo harías de esta manera con SAX? Creo que usar SAX de esa manera es demasiado complicado y se puede lograr de una manera más limpia con XPath (sin banderas, sin pila), solo mi opinión, aunque – eon

+1

Escribir una aplicación SAX es más trabajo, pero es perfectamente legítimo si necesita ahorrar memoria. que SAX ofrece y puede permitirse el esfuerzo adicional de programación para lograrlo. Sin embargo, creo que tiene razón en estar preocupado: alguien que necesita hacer la pregunta planteada en este hilo va a tener muchas dificultades para trabajar con SAX. –

0
private boolean isInStudentNode; 
...................................................  

public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 
    // enter node Student 
    if(qName.equalEgnoreCase("Student"){ 
     isInStudentNode = true; 
    } 
    ... 
} 

public void endElement(String uri, String localName, String qName) throws SAXException { 
    // end node Student 
    if(qName.equalEgnoreCase("Student"){ 
     isInStudentNode = false; 
     ........... 
    } 

    // end node Name (school|student) 
    if(qName.equalEgnoreCase("Name"){ 
     if(isInStudentNode) student.setName(...); 
     else school.setName(...); 
    } 
} 

su trabajo conmigo

Cuestiones relacionadas