Programujeme s XML (5.) - DOM v Javě II

Minule jsme si zopakovali načítání a ukládání dokumentů. Dnes se tedy podíváme, jak náš dokument propojíme s tabulkou.

29.6.2004 15:00 | Aleš Hakl | přečteno 15125×

Pokud chceme v komponentě JTable zobrazit vlastní data, je často nejrychlejší implementovat vlastní třídu odvozenou od třídy AbstractTableModel (tedy přesněji řečeno od třídy TableModel, ale AbstractTableModel nám poskytne některé užitečné pomocné metody.). Musíme tedy implementovat tyto metody:

Implementaci prvních tří metod a metody isCellEditable() rozebírat nebudu, v našem případě totiž nejsou vůbec zajímavé. Metoda getRowCount() v našem případě nepřistupuje přímo k dokumentu, ale pouze vrací hodnotu chráněné proměnné rowCount, jež je v odpovídajících metodách nastavováná, inkrementována a dekrementována. Vzhledem k tomu, že zbytek této ukázkové třídy je napsán silně neoptimálně, je to jen taková ukázka, jak by to také mohlo jít.

    public Object getValueAt(int row, int col) {
        Element it = ((Element)doc.getDocumentElement().getElementsByTagName("person").item(row));
        if (it==null) return null;
        Element el = (Element)it.getElementsByTagName(tags[col]).item(0);
        if (el==null) return null;
        Text text = (Text)el.getFirstChild();
        if (text==null) return null;
        return text.getData();
    }

Nejprve z kořenového elementu dokumentu vybereme všechny elementy s názvem "person", poté ze seznamu použijeme takový element, jaký nám udává parametr row. Pokud takový element neexistuje, získáme null, což na následujícím řádku ošetřujeme podmínkou. Z pole tags zjistíme název elementu odpovídajícího danému sloupci, a element uložíme do proměnné, celé je opět ošetřeno na výskyt hodnoty null. Z tohoto elementu použijeme první dceřiný uzel (tj. textový uzel, situace, že by se tam vyskytoval jiný uzel není ošetřena, opět je ošetřeno pouze kdyby žádný takový uzel neexistoval). Nakonec do volající metody (tj. nějakých vnitřností komponenty JTable) vrátíme obsah onoho prvního elementu.

    public void setValueAt(Object value, int row, int col) {
        Element it = ((Element)doc.getDocumentElement().getElementsByTagName("person").item(row));
        if (it==null) return;
        Element el = (Element)it.getElementsByTagName(tags[col]).item(0);
        if (el==null) return;
        Text newText = doc.createTextNode(value.toString());
        while (el.getFirstChild()!=null){
            el.removeChild(el.getFirstChild());
        }
        el.appendChild(newText);
    }

Metoda pro změnu obsahu buňky je nápadně podobná předchozí, středem je též nalezení odpovídajícího elementu, se kterým budeme manipulovat, tentokrát ovšem data nečteme, ale přepisujeme. Nejprve si vytvoříme nový textový uzel reprezentující novou hodnotu buňky (Není nejmenší důvod, proč toto dělat jako první krok, ale zdrojový kód přecejenom takto vypadá poněkud uhlazeněji.). Poté v cyklu smažeme všechny dceřiné uzly našeho elementu (je docela škoda, že autoři DOMu na toto nevyhradili speciální metodu). Nakonec vložíme nový obsah, tj. textový uzel, který jsme si dříve vytvořili.

Naše ukázka však není příliš optimální, bylo by vhodné v metodě setValueAt() vytvářet případné neexistující elementy (tj. <first-name />, <surname />, <phone /> a <email />) například nějak takto:

    public void setValueAt(Object value, int row, int col) {
        Element it = ((Element)doc.getDocumentElement().getElementsByTagName("person").item(row));
        if (it==null) return;
        Element el = (Element)it.getElementsByTagName(tags[col]).item(0);

        if (el==null) {
            el = doc.createElement(tags[col]);
            it.appendChild(el);
        };
        Text newText = doc.createTextNode(value.toString());
        while (el.getFirstChild()!=null){
            el.removeChild(el.getFirstChild());
        }
        el.appendChild(newText);
    }

Toto řešení by nám případně umožnilo odstranit vytváření těchto elementů z metody addItem(), na kterou se podíváme v dalším díle.

Další jistě užitečnou optimalizaci by představovalo umístění instance seznamu uzlů vraceného často používanou konstrukcí doc.getElementsByTagName("person") mezi chráněné proměnné spolu s dokumentem doc a výše uvedené volání provádět jen tehdy, je-li potřeba. Pravdou ovšem je, že toto by naší ukázku dost znepřehlednilo, ale zato ještě výrazněji zrychlilo, zvláště pokud bychom zpracovávali větší objemy dat.

Příště rozbor naší ukázky uzavřeme čtyřmi metodami implementujícími funkcionalitu čtyř tlačítek "Add", "Delete", "Move up" a "Move down" u dolní (jižní ^_~) hrany okna naší aplikace.

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=226