JavaRush /Java-Blog /Random-DE /XML-Grundlagen für den Java-Programmierer – Teil 3.1 von ...
Ярослав
Level 40
Днепр

XML-Grundlagen für den Java-Programmierer – Teil 3.1 von 3 – SAX

Veröffentlicht in der Gruppe Random-DE
Einleitung Hallo an alle Leser meines noch nicht letzten Artikels, und ich möchte Ihnen gratulieren: Die komplizierten Dinge rund um XML liegen hinter uns. Dieser Artikel enthält Code in Java. Es wird ein wenig Theorie und dann Praxis geben. Aufgrund der Tatsache, dass ein Material zu SAX in Word 10 Seiten ausfüllte, wurde mir klar, dass ich die Grenzen nicht einhalten konnte. Daher wird Artikel 3 in drei separate Artikel unterteilt, egal wie seltsam es klingen mag. Alles wird in dieser Reihenfolge sein: SAX -> DOM -> JAXB. Dieser Artikel konzentriert sich nur auf SAX. PS: Irgendwo im Kurs gab es eine Aufgabe, bei der es darum ging, alle internen Elemente in einer HTML-Datei anzuzeigen. Nach diesem Artikel können Sie dies tun, ohne Zeile für Zeile mit herkömmlichen BufferedReaderund komplexen Verarbeitungsalgorithmen zu lesen, und auch im letzten praktischen Beispiel wird eine ähnliche Lösung gegeben. Fangen wir an :) SAX (Simple API for XML) – THEORIE Der SAX-Handler ist so konzipiert, dass er XML-Dateien einfach sequentiell liest und auf verschiedene Ereignisse reagiert, wonach er die Informationen an einen speziellen Ereignishandler übergibt. Es gibt eine ganze Reihe von Ereignissen, aber die häufigsten und nützlichsten sind die folgenden:
  1. startDocument— der Anfang des Dokuments
  2. endDocument- Ende des Dokuments
  3. startElement- Öffnen eines Elements
  4. endElement- Schließen eines Elements
  5. characters— Textinformationen innerhalb von Elementen.
Alle Ereignisse werden in einem Ereignishandler verarbeitet , der erstellt und Methoden überschrieben werden müssen . Vorteile: hohe Leistung durch „direkte“ Datenauslesemethode, geringe Speicherkosten. Nachteile: eingeschränkte Funktionalität, was bedeutet, dass wir sie bei nichtlinearen Problemen verfeinern müssen. SAX (Simple API for XML) – PRAXIS Sofort eine Liste der Importe, damit Sie nichts suchen und verwechseln:
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;
Nun müssen wir zunächst einen SAXParser erstellen:
public class SAXExample {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // Schaffung фабрики и образца Parserа
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
    }
}
Wie Sie sehen, müssen Sie zunächst eine Fabrik erstellen und dann den Parser selbst in der Fabrik erstellen. Da wir nun den Parser selbst haben, benötigen wir einen Handler für seine Ereignisse. Hierfür benötigen wir für unsere eigene Bequemlichkeit eine separate Klasse:
public class SAXExample {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
    }

    private static class XMLHandler extends DefaultHandler {
        @Override
        public void startDocument() throws SAXException {
            // Тут будет логика реакции на начало dokumentierenа
        }

        @Override
        public void endDocument() throws SAXException {
            // Тут будет логика реакции на конец dokumentierenа
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            // Тут будет логика реакции на начало Element
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            // Тут будет логика реакции на конец Element
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            // Тут будет логика реакции на текст между Elementми
        }

        @Override
        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
            // Тут будет логика реакции на пустое пространство внутри элементов (пробелы, переносы строчек и так далее).
        }
    }
}
Wir haben eine Klasse mit allen Methoden erstellt, die wir zum Umgang mit Ereignissen benötigen, die in der Theorie aufgeführt sind. Etwas mehr zusätzliche Theorie: Etwas darüber characters: Wenn das Element Text enthält, zum Beispiel „ Hallo “, dann kann die Methode theoretisch fünfmal hintereinander für jedes einzelne Zeichen aufgerufen werden, aber das ist keine große Sache. Da wird alles noch funktionieren. Zu den startElementund- Methoden endElement:uri - Dies ist der Raum, in dem sich das Element befindet, localName- Dies ist der Name des Elements ohne Präfix, qName- Dies ist der Name des Elements mit Präfix (falls vorhanden, ansonsten nur der Name). des Elements). uriund localNameimmer leer, wenn wir die Raumverarbeitung in der Fabrik nicht aktiviert haben. Dies geschieht mit der Factory-Methode setNamespaceAware(true). uriDann können wir Leerzeichen ( ) und Elemente mit Präfixen davor ( ) erhalten localName. Aufgabe Nr. 1 – Wir haben das folgende XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
    <name>IT-Heaven</name>
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee name="Maksim" job="Middle Software Developer" />
                <employee name="Ivan" job="Junior Software Developer" />
                <employee name="Franklin" job="Junior Software Developer" />
            </employees>
        </office>
        <office floor="1" room="2">
            <employees>
                <employee name="Herald" job="Middle Software Developer" />
                <employee name="Adam" job="Middle Software Developer" />
                <employee name="Leroy" job="Junior Software Developer" />
            </employees>
        </office>
    </offices>
</company>
Unser Ziel: alle Informationen über alle Mitarbeiter aus dieser Datei zu erhalten. Zuerst müssen wir eine Klasse erstellenEmployee:
public class Employee {
    private String name, job;

    public Employee(String name, String job) {
        this.name = name;
        this.job = job;
    }

    public String getName() {
        return name;
    }

    public String getJob() {
        return job;
    }
}
Und in unserer Hauptklasse SAXExamplebrauchen wir eine Liste mit allen Mitarbeitern:
private static ArrayList<Employee> employees = new ArrayList<>();
Schauen wir uns nun genau an, wo sich die benötigten Informationen in der XML-Datei befinden. Und wie wir sehen, sind alle Informationen, die wir brauchen, die Attribute der Elemente employee. Und da startElementwir einen so nützlichen Parameter wie haben attributes, haben wir eine ziemlich einfache Aufgabe. Entfernen wir zunächst unnötige Methoden, um unseren Code nicht zu überladen. Wir brauchen nur die startElement. Und in der Methode selbst müssen wir Informationen aus den Attributen des Mitarbeitertags sammeln. Aufmerksamkeit:
public class SAXExample {
    private static ArrayList<Employee> employees = new ArrayList<>();

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
    }

    private static class XMLHandler extends DefaultHandler {
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if (qName.equals("employee")) {
                String name = attributes.getValue("name");
                String job = attributes.getValue("job");
                employees.add(new Employee(name, job));
            }
        }
    }
}
Die Logik ist einfach: Wenn der Name eines Elements lautet employee, erhalten wir lediglich Informationen über seine Attribute. Es attributesgibt eine nützliche Methode, mit der Sie durch Kenntnis des Namens eines Attributs dessen Wert ermitteln können. Das haben wir genutzt. Nachdem wir nun einen Event-Handler für den Anfang eines Elements erstellt haben, müssen wir unsere XML-Datei analysieren . Gehen Sie dazu einfach wie folgt vor:
public class SAXExample {
    private static ArrayList<Employee> employees = new ArrayList<>();

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();

        XMLHandler handler = new XMLHandler();
        parser.parse(new File("resource/xml_file1.xml"), handler);

        for (Employee employee : employees)
            System.out.println(String.format("Name сотрудника: %s, его должность: %s", employee.getName(), employee.getJob()));
    }

    private static class XMLHandler extends DefaultHandler {
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if (qName.equals("employee")) {
                String name = attributes.getValue("name");
                String job = attributes.getValue("job");
                employees.add(new Employee(name, job));
            }
        }
    }
}
In der Parse-Methode müssen Sie den Pfad zur XML-Datei und den von Ihnen erstellten Handler übergeben. Und so haben wir mithilfe dieses Codes Informationen aus diesem XML extrahiert:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
    <name>IT-Heaven</name>
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee name="Maksim" job="Middle Software Developer" />
                <employee name="Ivan" job="Junior Software Developer" />
                <employee name="Franklin" job="Junior Software Developer" />
            </employees>
        </office>
        <office floor="1" room="2">
            <employees>
                <employee name="Herald" job="Middle Software Developer" />
                <employee name="Adam" job="Middle Software Developer" />
                <employee name="Leroy" job="Junior Software Developer" />
            </employees>
        </office>
    </offices>
</company>
Und wir haben die folgende Ausgabe erhalten:
Name сотрудника: Maksim, его должность: Middle Software Developer
Name сотрудника: Ivan, его должность: Junior Software Developer
Name сотрудника: Franklin, его должность: Junior Software Developer
Name сотрудника: Herald, его должность: Middle Software Developer
Name сотрудника: Adam, его должность: Middle Software Developer
Name сотрудника: Leroy, его должность: Junior Software Developer
Mission erfüllt! Aufgabe Nr. 2 – wir haben das folgende XML:
<?xml version="1.0" encoding="UTF-8"?>
<company>
    <name>IT-Heaven</name>
    <offices>
        <office floor="1" room="1">
            <employees>
                <employee>
                    <name>Maksim</name>
                    <job>Middle Software Developer</job>
                </employee>
                <employee>
                    <name>Ivan</name>
                    <job>Junior Software Developer</job>
                </employee>
                <employee>
                    <name>Franklin</name>
                    <job>Junior Software Developer</job>
                </employee>
            </employees>
        </office>
        <office floor="1" room="2">
            <employees>
                <employee>
                    <name>Herald</name>
                    <job>Middle Software Developer</job>
                </employee>
                <employee>
                    <name>Adam</name>
                    <job>Middle Software Developer</job>
                </employee>
                <employee>
                    <name>Leroy</name>
                    <job>Junior Software Developer</job>
                </employee>
            </employees>
        </office>
    </offices>
</company>
Unser Ziel: alle Informationen über alle Mitarbeiter aus dieser Datei zu erhalten. Dieses Problem zeigt deutlich, wie eine schlecht strukturierte XML-Datei das Schreiben von Code erschweren kann. Wie Sie sehen können, werden Informationen zu Name und Position jetzt als Textinformationen in den Elementen nameund gespeichert job. Um Text innerhalb von Elementen zu lesen, haben wir die Zeichenmethode. Dazu müssen wir eine neue Handler-Klasse mit verbesserter Logik erstellen. Vergessen Sie nicht, dass Handler vollwertige Klassen sind, die Logik beliebiger Komplexität speichern können. Deshalb werden wir jetzt unseren Prozessor optimieren. Tatsächlich reicht es zu beachten, dass wir uns immer nameabwechseln job, und egal in welcher Reihenfolge, wir können den Namen und den Beruf ganz einfach in separaten Variablen speichern und wenn beide Variablen gespeichert sind, unseren Mitarbeiter erstellen. Nur haben wir hier neben dem Anfang des Elements keinen Parameter für den Text innerhalb des Elements. Wir müssen Methoden auf Text anwenden. Aber wie bekommen wir Textinformationen in ein Element, wenn es sich dabei um völlig unterschiedliche Methoden handelt? Meine Lösung: Wir müssen uns nur den Namen des letzten Elements merken und charactersprüfen, in welchem ​​Element wir die Informationen lesen. Sie müssen auch bedenken, dass <codee>characters alle Zeichen innerhalb von Elementen liest, was bedeutet, dass alle Leerzeichen und sogar Zeilenumbrüche gelesen werden. Und wir brauchen sie nicht. Wir müssen diese Daten ignorieren, da sie falsch sind.</codee> Code:
public class SAXExample {
    private static ArrayList<Employee> employees = new ArrayList<>();

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();

        AdvancedXMLHandler handler = new AdvancedXMLHandler();
        parser.parse(new File("resource/xml_file2.xml"), handler);

        for (Employee employee : employees)
            System.out.println(String.format("Name сотрудника: %s, его должность: %s", employee.getName(), employee.getJob()));
    }

    private static class AdvancedXMLHandler extends DefaultHandler {
        private String name, job, lastElementName;

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            lastElementName = qName;
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            String information = new String(ch, start, length);

            information = information.replace("\n", "").trim();

            if (!information.isEmpty()) {
                if (lastElementName.equals("name"))
                    name = information;
                if (lastElementName.equals("job"))
                    job = information;
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if ( (name != null && !name.isEmpty()) && (job != null && !job.isEmpty()) ) {
                employees.add(new Employee(name, job));
                name = null;
                job = null;
            }
        }
    }
}
Wie Sie sehen, ist unser Code aufgrund der banalen Komplikation der XML-Dateistruktur deutlich komplizierter geworden. Der Code ist jedoch nicht kompliziert. Beschreibung: Wir haben Variablen erstellt, um Daten über den Mitarbeiter ( name, job) zu speichern , sowie eine Variable, lastElementNameum aufzuzeichnen, in welchem ​​Element wir uns befinden. Danach charactersfiltern wir in der Methode die Informationen, und wenn dort noch Informationen vorhanden sind, bedeutet dies, dass dies der Text ist, den wir benötigen, und dann bestimmen wir mithilfe von , ob es sich um einen Namen oder einen Beruf handelt lastElementName. Bei der Methode endElementprüfen wir, ob alle Informationen gelesen wurden, und wenn ja, erstellen wir einen Mitarbeiter und setzen die Informationen zurück. Die Ausgabe der Lösung entspricht dem ersten Beispiel:
Name сотрудника: Maksim, его должность: Middle Software Developer
Name сотрудника: Ivan, его должность: Junior Software Developer
Name сотрудника: Franklin, его должность: Junior Software Developer
Name сотрудника: Herald, его должность: Middle Software Developer
Name сотрудника: Adam, его должность: Middle Software Developer
Name сотрудника: Leroy, его должность: Junior Software Developer
Somit wurde dieses Problem gelöst , aber Sie können feststellen, dass die Komplexität höher ist. Daraus können wir schließen, dass die Speicherung von Textinformationen in Attributen meistens korrekter ist als in einzelnen Elementen. Und noch eine nette Aufgabe, die das Problem in JavaRush mit der Anzeige von Informationen zu einem Element in HTML teilweise lösen wird, nur muss es ein wenig bearbeitet werden, hier werden wir einfach alle Elemente innerhalb eines Elements auflisten :) Aufgabe Nr. 3 – Zeigt bei gegebenem Elementelement die Namen und Attribute aller internen Elemente an. Wenn das Element nicht gefunden wird, wird dies angezeigt. Für diese Aufgabe verwenden wir die folgende XML-Datei:
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <oracle>
        <connection value="jdbc:oracle:thin:@10.220.140.48:1521:test1" />
        <user value="secretOracleUsername" />
        <password value="111" />
    </oracle>

    <mysql>
        <connection value="jdbc:mysql:thin:@10.220.140.48:1521:test1" />
        <user value="secretMySQLUsername" />
        <password value="222" />
    </mysql>
</root>
Wie Sie sehen, haben wir hier drei mögliche Szenarien: root, mysql, oracle. Anschließend zeigt das Programm alle Informationen zu allen darin enthaltenen Elementen an. Wie können wir das machen? Und es ist ganz einfach: Wir müssen nur eine logische Variable deklarieren isEntered, die angibt, ob wir das darin enthaltene Element benötigen, und wenn es darin enthalten ist, alle Daten daraus lesen startElement. Lösungscode:
public class SAXExample {
    private static boolean isFound;

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();

        SearchingXMLHandler handler = new SearchingXMLHandler("root");
        parser.parse(new File("resource/xml_file3.xml"), handler);

        if (!isFound)
            System.out.println("Элемент не был найден.");
    }

    private static class SearchingXMLHandler extends DefaultHandler {
        private String element;
        private boolean isEntered;

        public SearchingXMLHandler(String element) {
            this.element = element;
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if (isEntered) {
                System.out.println(String.format("Найден элемент <%s>, его атрибуты:", qName));

                int length = attributes.getLength();
                for(int i = 0; i < length; i++)
                    System.out.println(String.format("Name атрибута: %s, его Bedeutung: %s", attributes.getQName(i), attributes.getValue(i)));
            }

            if (qName.equals(element)) {
                isEntered = true;
                isFound = true;
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if (qName.equals(element))
                isEntered = false;
        }
    }
}
Wenn wir in diesem Code ein Element eingeben, über das wir Informationen benötigen, setzen wir das Flag isEnteredauf true, was bedeutet, dass wir uns innerhalb des Elements befinden. Und sobald wir uns im Element befinden, verarbeiten wir einfach jedes neue Element startElementim Wissen, dass es sich genau um ein internes Element unseres Elements handelt. Also geben wir den Elementnamen und seinen Titel aus. Wenn das Element in der Datei nicht gefunden wurde, haben wir eine Variable, isFounddie gesetzt wird, wenn das Element gefunden wird. Wenn sie falsch ist, wird eine Meldung angezeigt, dass das Element nicht gefunden wurde. SearchingXMLHandlerUnd wie Sie sehen können, haben wir im Beispiel rootein Element an den Konstruktor übergeben. Fazit für ihn:
Найден элемент <oracle>, его атрибуты:
Найден элемент <connection>, его атрибуты:
Name атрибута: value, его Bedeutung: jdbc:oracle:thin:@10.220.140.48:1521:test1
Найден элемент <user>, его атрибуты:
Name атрибута: value, его Bedeutung: secretOracleUsername
Найден элемент <password>, его атрибуты:
Name атрибута: value, его Bedeutung: 111
Найден элемент <mysql>, его атрибуты:
Найден элемент <connection>, его атрибуты:
Name атрибута: value, его Bedeutung: jdbc:mysql:thin:@10.220.140.48:1521:test1
Найден элемент <user>, его атрибуты:
Name атрибута: value, его Bedeutung: secretMySQLUsername
Найден элемент <password>, его атрибуты:
Name атрибута: value, его Bedeutung: 222
Somit haben wir alle Informationen über die internen Elemente und deren Attribute erhalten. Das Problem ist behoben. <h2>Epilog</h2>Sie haben gesehen, dass SAX ein recht interessantes und sehr effektives Werkzeug ist und auf unterschiedliche Weise, für verschiedene Zwecke usw. verwendet werden kann. Sie müssen das Problem nur von rechts betrachten Seite, wie in Aufgabe Nr. 2 und Nr. 3 gezeigt, wo SAX keine direkten Methoden zur Lösung des Problems bereitstellte, wir aber dank unseres Einfallsreichtums einen Ausweg aus der Situation finden konnten. Der nächste Teil des Artikels ist ausschließlich dem DOM gewidmet. Ich hoffe, es hat Ihnen Spaß gemacht, SAX kennenzulernen. Experimentieren Sie, üben Sie und Sie werden verstehen, dass alles ganz einfach ist. Und das ist alles, viel Glück beim Programmieren und freuen uns auf den baldigen Teil über das DOM. Viel Erfolg beim Studium :) Vorheriger Artikel: [Wettbewerb] XML-Grundlagen für einen Java-Programmierer – Teil 2 von 3 Nächster Artikel: [Wettbewerb] XML-Grundlagen für einen Java-Programmierer – Teil 3.2 von 3 – DOM
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION