JavaRush /Java Blog /Random-TL /Mga Pangunahing Kaalaman sa XML para sa Java Programmer -...
Ярослав
Antas
Днепр

Mga Pangunahing Kaalaman sa XML para sa Java Programmer - Bahagi 3.1 ng 3 - SAX

Nai-publish sa grupo
Panimula Kumusta sa lahat ng mga mambabasa ng aking hindi pa huling artikulo, at nais kong batiin ka: ang mga masalimuot na bagay tungkol sa XML ay nasa likod namin. Ang artikulong ito ay maglalaman ng code sa Java. Magkakaroon ng isang maliit na teorya, at pagkatapos ay pagsasanay. Dahil sa katotohanan na ang isang piraso ng materyal sa SAX ay napuno ng 10 mga pahina sa Word, natanto ko na hindi ako magkasya sa mga limitasyon. Samakatuwid, ang artikulo 3 ay hahatiin sa 3 magkahiwalay na artikulo, gaano man ito kakaiba. Ang lahat ay magiging sa ganitong pagkakasunud-sunod: SAX -> DOM -> JAXB. Ang artikulong ito ay tututuon lamang sa SAX. PS Mayroong isang gawain sa isang lugar sa kurso kung saan kinakailangan upang ipakita ang lahat ng mga panloob na elemento sa isang HTML file. Pagkatapos ng artikulong ito, magagawa mo ito nang hindi nagbabasa ng linya sa pamamagitan ng linya na may kumbensyonal BufferedReaderat kumplikadong mga algorithm sa pagproseso, at isang katulad na solusyon ang ibibigay sa huling praktikal na halimbawa. Magsimula na tayo :) SAX (Simple API para sa XML) - TEORY Ang tagapangasiwa ng SAX ay idinisenyo sa paraang binabasa lamang nito ang mga XML file nang sunud-sunod at tumutugon sa iba't ibang mga kaganapan, pagkatapos nito ay ipinapasa nito ang impormasyon sa isang espesyal na tagapangasiwa ng kaganapan. Mayroon itong medyo ilang mga kaganapan, ngunit ang pinaka-madalas at kapaki-pakinabang ay ang mga sumusunod:
  1. startDocument— ang simula ng dokumento
  2. endDocument- dulo ng dokumento
  3. startElement- pagbubukas ng isang elemento
  4. endElement- pagsasara ng isang elemento
  5. characters— impormasyon ng teksto sa loob ng mga elemento.
Ang lahat ng mga kaganapan ay pinoproseso sa isang tagapangasiwa ng kaganapan , na dapat gawin at ang mga pamamaraan ay na-override . Mga kalamangan: mataas na pagganap dahil sa "direktang" paraan ng pagbabasa ng data, mababang gastos sa memorya. Mga disadvantages: limitadong pag-andar, na nangangahulugang sa mga hindi linear na problema ay kailangan nating pinuhin ito. SAX (Simple API para sa XML) – MAG-PRACTICE kaagad ng listahan ng mga import para hindi ka maghanap at malito ng anuman:
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;
Ngayon, una, kailangan nating lumikha ng SAXParser:
public class SAXExample {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        // Creation фабрики и образца parserа
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
    }
}
Tulad ng nakikita mo, kailangan mo munang lumikha ng isang pabrika, at pagkatapos ay lumikha ng parser mismo sa pabrika. Ngayon na mayroon na tayong parser mismo, kailangan natin ng handler para sa mga kaganapan nito. Para dito kailangan namin ng isang hiwalay na klase para sa aming sariling kaginhawahan:
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 {
            // Тут будет логика реакции на начало documentа
        }

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

        @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 {
            // Тут будет логика реакции на пустое пространство внутри элементов (пробелы, переносы строчек и так далее).
        }
    }
}
Gumawa kami ng isang klase na may lahat ng mga pamamaraan na kailangan namin upang mahawakan ang mga kaganapan na nakalista sa teorya. Karagdagang karagdagang teorya: Kaunti tungkol sa characters: kung ang elemento ay naglalaman ng teksto, halimbawa, " hello ", kung gayon, ayon sa teorya, ang pamamaraan ay maaaring tawaging 5 beses sa isang hilera para sa bawat indibidwal na karakter, ngunit hindi ito nakakatakot, dahil ang lahat gagana pa rin. Tungkol sa startElementat mga pamamaraan endElement:uri - ito ang puwang kung saan matatagpuan ang elemento, localName- ito ang pangalan ng elemento na walang prefix, qName- ito ang pangalan ng elemento na may prefix (kung mayroon man, kung hindi man ay pangalan lang ng elemento). uriat localNamepalaging walang laman kung hindi namin pinagana ang pagpoproseso ng espasyo sa pabrika. Ginagawa ito gamit ang factory method setNamespaceAware(true). Pagkatapos ay makakakuha tayo ng espasyo ( uri) at mga elemento na may mga prefix sa harap ng mga ito ( localName). Gawain #1 - Mayroon kaming sumusunod na 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>
Ang aming layunin: makuha ang lahat ng impormasyon tungkol sa lahat ng empleyado mula sa file na ito. Una, kailangan nating lumikha ng isang klaseEmployee:
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;
    }
}
At sa aming pangunahing klase SAXExamplekailangan namin ng isang listahan kasama ang lahat ng mga empleyado:
private static ArrayList<Employee> employees = new ArrayList<>();
Ngayon tingnan nating mabuti kung nasaan ang impormasyong kailangan natin sa XML file. At, tulad ng nakikita natin, ang lahat ng impormasyong kailangan natin ay ang mga katangian ng mga elemento employee. At dahil startElementmayroon kaming isang kapaki-pakinabang na parameter bilang attributes, kung gayon mayroon kaming isang medyo simpleng gawain. Una, alisin natin ang mga hindi kinakailangang pamamaraan upang hindi makalat ang ating code. Kailangan lang natin ang startElement. At sa mismong pamamaraan, dapat tayong mangolekta ng impormasyon mula sa mga katangian ng tag ng empleyado. Pansin:
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));
            }
        }
    }
}
Ang lohika ay simple: kung ang pangalan ng isang elemento ay employee, tatanggap lang kami ng impormasyon tungkol sa mga katangian nito. Mayroong attributesisang kapaki-pakinabang na paraan kung saan, alam ang pangalan ng isang katangian, maaari mong makuha ang halaga nito. Yan ang ginamit namin. Ngayong nakagawa na kami ng event handler para sa simula ng isang elemento, kailangan naming i-parse ang aming XML file . Upang gawin ito, gawin lamang ito:
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));
            }
        }
    }
}
Sa paraan ng pag-parse dapat mong ipasa ang landas sa xml file at ang handler na iyong nilikha. At kaya, gamit ang code na ito kinuha namin ang impormasyon mula sa XML na ito:
<?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>
At nakuha namin ang sumusunod na output:
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
Natupad ang misyon! Gawain #2 - mayroon kaming sumusunod na 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>
Ang aming layunin: makuha ang lahat ng impormasyon tungkol sa lahat ng empleyado mula sa file na ito. Ipapakita ng problemang ito kung paano maaaring gawing mas mahirap ng isang hindi maayos na structured na XML file ang pagsulat ng code. Gaya ng nakikita mo, ang impormasyon tungkol sa pangalan at posisyon ay nakaimbak na ngayon bilang impormasyon ng teksto sa loob ng nameat mga elemento job. Upang basahin ang teksto sa loob ng mga elemento, mayroon kaming paraan ng mga character. Para magawa ito, kailangan nating lumikha ng bagong klase ng handler na may pinahusay na lohika. Huwag kalimutan na ang mga humahawak ay ganap na mga klase na may kakayahang mag-imbak ng lohika ng anumang kumplikado. Samakatuwid, ngayon ay i-tune namin ang aming processor. Sa katunayan, sapat na upang tandaan na palagi kaming namenagpapalitan job, at hindi mahalaga kung anong pagkakasunud-sunod, madali naming mai-save ang pangalan at propesyon sa magkahiwalay na mga variable, at kapag ang parehong mga variable ay na-save, lumikha ng aming empleyado. Dito lamang, kasama ang simula ng elemento, wala kaming parameter para sa teksto sa loob ng elemento. Kailangan nating gumamit ng mga pamamaraan sa teksto. Ngunit paano tayo makakakuha ng impormasyon ng teksto sa loob ng isang elemento kung ito ay ganap na magkakaibang mga pamamaraan? Ang aking solusyon: kailangan lang nating tandaan ang pangalan ng huling elemento, at characterssuriin kung aling elemento ang binabasa natin ang impormasyon. Kailangan mo ring tandaan na ang <codee>character ay nagbabasa ng lahat ng mga character sa loob ng mga elemento, na nangangahulugan na ang lahat ng mga puwang at kahit na mga line break ay mababasa. At hindi natin sila kailangan. Kailangan nating balewalain ang data na ito dahil mali ito.</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;
            }
        }
    }
}
Tulad ng nakikita mo, dahil sa karaniwang komplikasyon ng istraktura ng XML file, ang aming code ay naging mas kumplikado. Gayunpaman, ang code ay hindi kumplikado. Paglalarawan: gumawa kami ng mga variable upang mag-imbak ng data tungkol sa empleyado ( name, job) , pati na rin ang isang variable lastElementNameupang itala kung aling elemento ang nasa loob namin. Pagkatapos nito, sa pamamaraan charactersay sinasala namin ang impormasyon, at kung mayroon pa ring impormasyon doon, nangangahulugan ito na ito ang teksto na kailangan namin, at pagkatapos ay tinutukoy namin kung ito ay isang pangalan o isang propesyon na gumagamit ng lastElementName. Sa pamamaraan endElement, sinusuri namin kung nabasa na ang lahat ng impormasyon, at kung gayon, lumikha kami ng empleyado at ni-reset ang impormasyon. Ang output ng solusyon ay katumbas ng unang halimbawa:
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
Kaya, ang problemang ito ay nalutas na , ngunit maaari mong mapansin na ang pagiging kumplikado ay mas mataas. Samakatuwid, maaari nating tapusin na ang pag-iimbak ng impormasyon ng teksto sa mga katangian ay kadalasang magiging mas tama kaysa sa mga indibidwal na elemento. At isa pang matamis na gawain na bahagyang malulutas ang problema sa JavaRush tungkol sa pagpapakita ng impormasyon tungkol sa isang elemento sa HTML, kailangan lang itong i-edit ng kaunti, dito ay ililista lang namin ang lahat ng mga elemento sa loob ng isang elemento :) Gawain No. 3 - ibinigay ang elemento ng elemento, ipakita ang mga pangalan at katangian ng lahat ng panloob na elemento; kung ang elemento ay hindi natagpuan, ipakita ito. Para sa gawaing ito gagamitin namin ang sumusunod na XML file:
<?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>
Gaya ng nakikita mo, mayroon kaming tatlong posibleng mga sitwasyon dito: root, mysql, oracle. Pagkatapos ay ipapakita ng programa ang lahat ng impormasyon tungkol sa lahat ng mga elemento sa loob. Paano natin ito magagawa? At ito ay medyo simple: kailangan lang nating magdeklara ng isang lohikal na variable isEntered, na magsasaad kung kailangan natin ang elemento sa loob, at kung nasa loob, basahin ang lahat ng data mula sa startElement. Code ng solusyon:
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, его meaning: %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;
        }
    }
}
Sa code na ito, kapag nagpapasok ng isang elemento kung saan kailangan namin ng impormasyon, itinakda namin ang bandila isEnteredsa true, na nangangahulugang nasa loob kami ng elemento. At sa sandaling nasa loob na kami ng elemento, pinoproseso lang namin ang bawat bagong elemento startElement, alam na ito ay eksaktong panloob na elemento ng aming elemento. Kaya inilabas namin ang pangalan ng elemento at ang pamagat nito. Kung hindi nakita ang elemento sa file, mayroon kaming variable isFoundna itinakda kapag natagpuan ang elemento, at kung mali ito, may ipapakitang mensahe na hindi natagpuan ang elemento. At tulad ng nakikita mo, sa halimbawa ay SearchingXMLHandleripinasa namin rootang isang elemento sa constructor. Konklusyon para sa kanya:
Найден элемент <oracle>, его атрибуты:
Найден элемент <connection>, его атрибуты:
Name атрибута: value, его meaning: jdbc:oracle:thin:@10.220.140.48:1521:test1
Найден элемент <user>, его атрибуты:
Name атрибута: value, его meaning: secretOracleUsername
Найден элемент <password>, его атрибуты:
Name атрибута: value, его meaning: 111
Найден элемент <mysql>, его атрибуты:
Найден элемент <connection>, его атрибуты:
Name атрибута: value, его meaning: jdbc:mysql:thin:@10.220.140.48:1521:test1
Найден элемент <user>, его атрибуты:
Name атрибута: value, его meaning: secretMySQLUsername
Найден элемент <password>, его атрибуты:
Name атрибута: value, его meaning: 222
Kaya, natanggap namin ang lahat ng impormasyon tungkol sa mga panloob na elemento at kanilang mga katangian. Ang problema ay nalutas. <h2>Epilogue</h2>Nakita mo na ang SAX ay isang kawili-wiling tool at medyo epektibo, at maaari itong magamit sa iba't ibang paraan, para sa iba't ibang layunin, at iba pa, kailangan mo lang tingnan ang problema mula sa kanan. side, tulad ng ipinapakita sa gawain No. 2 at No. 3, kung saan ang SAX ay hindi nagbigay ng mga direktang pamamaraan para sa paglutas ng problema, ngunit, salamat sa aming katalinuhan, nakagawa kami ng paraan para makaalis sa sitwasyon. Ang susunod na bahagi ng artikulo ay ganap na nakatuon sa DOM. Sana ay nasiyahan ka sa pagkilala kay SAX. Mag-eksperimento, magsanay at mauunawaan mo na ang lahat ay medyo simple. At iyon lang, good luck sa iyong programming at abangan ang bahagi tungkol sa DOM sa lalong madaling panahon. Good luck sa iyong pag-aaral :) Nakaraang artikulo: [Kumpetisyon] Mga Pangunahing Kaalaman sa XML para sa isang Java Programmer - Bahagi 2 ng 3 Susunod na artikulo: [Kumpetisyon] Mga Pangunahing Kaalaman sa XML para sa isang Java Programmer - Bahagi 3.2 ng 3 - DOM
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION