Vytažení dat z XML v Javě

Dr.Who

Vytažení dat z XML v Javě
« kdy: 27. 03. 2015, 14:01:05 »
Cau,
prostrednictvim podobneho kodu http://www.java2s.com/Code/JavaAPI/org.w3c.dom/ElementNodeListgetChildNodes.htm  jsem zkousel z nasledujiciho XML dostat hodnotu z promenne ct na radku CS id="3", ale beznadejne.

Kód: [Vybrat]
<Snapshot id="142102345">
<Stats name="runtime" statType="moduleRuntime" il="-2">
<CS id="2" sT="1422004481541" lST="1427376591432" ct="225331">
</CS>
<CS id="3" sT="1422004481541" lST="1427376591432" ct="503459"> 
</CS>
<CS id="5" sT="1422004481541" lST="1427376591432" ct="0">
</Stats>
</Snapshot>

Je nejaka jina cesta nez getChildNodes, ktera mi pomuze vytahat hodnoty ct?
« Poslední změna: 27. 03. 2015, 18:37:40 od Petr Krčmář »


Zaprdeny deda

Re:vytahnuti dat z XML
« Odpověď #1 kdy: 27. 03. 2015, 14:26:25 »
Jakou knihovnu na XML pouzivas? Je jich vic, jedna je naprosto debilni a nema na to funkce, jina umoznuje pristup primo na konkretni childnode, kdyz znas jeho jmeno. Uz je to dlouho, co jsem to pouzival, najdi si jak to ruzny knihovny resi.

Zaprdeny deda

Re:vytahnuti dat z XML
« Odpověď #2 kdy: 27. 03. 2015, 14:27:38 »
Aha, w3c.org neni ta nejlepsi XML knihovna.

Filip Jirsák nepřihlášený

Re:vytahnuti dat z XML
« Odpověď #3 kdy: 27. 03. 2015, 14:38:36 »
XPath. Pro Javu existují různé implementace, např. Jaxen, Saxon. Také pro práci s XML existují vhodnější knihovny, než W3C DOM – DOM4J, JDOM, XOM.

Např. v DOM4J použijete přibližně takovýhle kód:
Kód: [Vybrat]
result = document.selectSingleNode("/Snapshot/Stats/CS[@id='3']/@ct");

Dr.Who

Re:Vytažení dat z XML v Javě
« Odpověď #4 kdy: 07. 04. 2015, 09:54:24 »
Povedlo se mi pomoci jednoho prikladu na netu dostat prvni hodnoty ze souboru XML. Potrebuji ale v jednom "for" dostat vicero hodnot atributu.
Pokousel sem se Xpath rozsirit, ale bez uspechu


Kód: [Vybrat]

         XPath xPath =  XPathFactory.newInstance().newXPath();

         String expression = "//Stats[@name='jvmRuntimeModule']/CS[@id='2'] | //Stats[@name='systemModule']/CS[@id='1'] | //Stats[@name='connectionPoolModule']/RS[@id='9']";
         NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(doc, XPathConstants.NODESET);
         for (int i = 0; i < nodeList.getLength(); i++) {
            Node nNode = nodeList.item(i);
            System.out.println("\nCurrent Element :"
               + nNode.getNodeName());
            if (nNode.getNodeType() == Node.ELEMENT_NODE) {
               Element eElement = (Element) nNode;

               System.out.println("Value : "
                  + eElement.getAttribute("ct") + eElement.getAttribute("ct") + eElement.getAttribute("cur"));
                System.out.println("*****************************************");
            }


         }






Filip Jirsák nepřihlášený

Re:Vytažení dat z XML v Javě
« Odpověď #5 kdy: 07. 04. 2015, 11:36:19 »
Ten XPath výraz máte správně.

S dom4j by to bylo

Kód: [Vybrat]
List<Element> elements = (List<Element>) document.selectNodes(
    "//Stats[@name='jvmRuntimeModule']/CS[@id='2'] |" +
    "//Stats[@name='systemModule']/CS[@id='1'] | " +
    "//Stats[@name='connectionPoolModule']/RS[@id='9']"
);
for (Element element : elements) {
  System.out.printf("Value: %s%s%s",
      element.attributeValue("ct"),
      element.attributeValue("ct"),
      element.attributeValue("cur")
    ).println();
  System.out.println("*****************************************");
}

S W3C DOM vám asi nikdo neporadí, protože to nikdo nepoužívá. Není důvod používat tohle složité API, když existuje spousta alternativ, které toho umějí víc a jsou mnohem jednodušší na použití.

Dr.Who

Re:Vytažení dat z XML v Javě
« Odpověď #6 kdy: 07. 04. 2015, 17:38:16 »
Ten XPath výraz máte správně.

S dom4j by to bylo

Kód: [Vybrat]
List<Element> elements = (List<Element>) document.selectNodes(
    "//Stats[@name='jvmRuntimeModule']/CS[@id='2'] |" +
    "//Stats[@name='systemModule']/CS[@id='1'] | " +

);
for (Element element : elements) {
  System.out.printf("Value: %s%s%s",
      element.attributeValue("ct"),
      element.attributeValue("ct"),
 
    ).println();
  System.out.println("*****************************************");
}

S W3C DOM vám asi nikdo neporadí, protože to nikdo nepoužívá. Není důvod používat tohle složité API, když existuje spousta alternativ, které toho umějí víc a jsou mnohem jednodušší na použití.

Dekuju moc! Akorat mam problem, ze se mi nedari zmenit vystup

dostavam:


24440 24440
*********************************
65  65 
*********************************

Jak muzu donutit for, abych mel na radku oboje hodnoty? tzn

24440[to je hodnota prvniho ct]  65[hodnota druheho ct]

Filip Jirsák nepřihlášený

Re:Vytažení dat z XML v Javě
« Odpověď #7 kdy: 07. 04. 2015, 18:21:44 »
V tom vašem příkladu jste vypisoval dvakrát za sebou hodnotu jednoho atributu u stejného elementu. Nedávalo mi to smysl, ale opsal jsem to tak i do mého řešení.

Jaké „oboje hodnoty“ tam chcete mít? Každý element může mít pouze jeden atribut daného jména.

Ty XPtah výrazy, které jste napsal, neodpovídají tomu XML na začátku. Nejlepší by bylo, kdybyste sem dal celé XML nebo alespoň jeho relevantní část, a napsal, co z něj vlastně chcete získat.

Dr.Who

Re:Vytažení dat z XML v Javě
« Odpověď #8 kdy: 08. 04. 2015, 08:45:31 »
Kód: [Vybrat]
<TPVLog>
<Snapshot time="1422004481541">
<Stats name="jvmRuntimeModule" statType="jvmRuntimeModule#" il="-2" type="COLLECTION">
<CS id="2" sT="1422004481541" lST="1427376440605" ct="234457">
</CS>
<Stats name="systemModule" statType="systemModule" il="-2" type="MODULE">
<CS id="1" sT="1427192170123" lST="1427376470956" ct="61">
</CS>
</Snapshot>
</TPVLog>

Je jich tam pod sebou vice to je jenom pro ilustraci. Atribut CT v kazdem nodu?  vyjadruje pozadovanou hodnotu, kterou si potrebuju vyexportovat


Zdenek Henek

Re:Vytažení dat z XML v Javě
« Odpověď #9 kdy: 08. 04. 2015, 09:46:11 »
Je jich tam pod sebou vice to je jenom pro ilustraci. Atribut CT v kazdem nodu?  vyjadruje pozadovanou hodnotu, kterou si potrebuju vyexportovat

Jestli jich je tam opravdu hodne(stovky MB)  a toto neni jen domaci ukol do skoly s tim, ze uz to nikdy neuvidite, tak bych doporucoval pouzit Sax nebo Stax knihovnu a zpracovavat xml postupne, aby to nespotrebovalo zbytecne moc pameti. Tyto knihovny jsou slozitejsi na pouziti, ale pokud to xml ve finale bude opravdu velke, tak jinou rozumnou moznost nevidim.

https://docs.oracle.com/javase/tutorial/jaxp/sax/parsing.html
https://docs.oracle.com/javase/tutorial/jaxp/stax/why.html

Dalsi moznost je JAXB. http://www.oracle.com/technetwork/articles/javase/index-140168.html
Pokud mate schema tak muzete xml parser vygenerovat a pak uz jen pouzivat java objekty. Toto jsem nikdy nepouzil na velkych xml souborech. Pouzival jsem Stax parser a ve chvili, kdy jsem narazil na element, ktery mel slozitou strukturu(ale nebyl velky), tak jsem pouzil JAXB.

Jeste k tomu schema. Pokud zadne nemate, tak doporucuji vytvorit a pouzivat. Cloveku nic nezkazi den vic nez zjisteni, ze uz par hodin hleda chybu v kodu a vstupni xml je starsi verze :)

j

Re:Vytažení dat z XML v Javě
« Odpověď #10 kdy: 08. 04. 2015, 09:46:55 »
Kód: [Vybrat]
<TPVLog>
<Snapshot time="1422004481541">
<Stats name="jvmRuntimeModule" statType="jvmRuntimeModule#" il="-2" type="COLLECTION">
<CS id="2" sT="1422004481541" lST="1427376440605" ct="234457">
</CS>
<Stats name="systemModule" statType="systemModule" il="-2" type="MODULE">
<CS id="1" sT="1427192170123" lST="1427376470956" ct="61">
</CS>
</Snapshot>
</TPVLog>

Je jich tam pod sebou vice to je jenom pro ilustraci. Atribut CT v kazdem nodu?  vyjadruje pozadovanou hodnotu, kterou si potrebuju vyexportovat

Vsak jo, cyklus bezi pres ty radky, tak ze v kazdym cyklu lze vypsat jednu hodnotu, ne 2, 3, 4 ...

perceptron

Re:Vytažení dat z XML v Javě
« Odpověď #11 kdy: 08. 04. 2015, 11:23:37 »
nepovedali ste co to je za zadanie. chcete vsetky ct alebo len pre dany riadok?

jaxb je na tento task overkill

riesenie cez stream sax

https://gist.github.com/anonymous/0757f4f1c6c11fe0f026

Filip Jirsák nepřihlášený

Re:Vytažení dat z XML v Javě
« Odpověď #12 kdy: 08. 04. 2015, 11:35:23 »
Pro každý element Snapshot tedy chcete vypsat tu trojici?

Kód: [Vybrat]
Element root = document.getRootElement();
for (Element snapshotElement : (List<Element>) root.elements("Snapshot")) {
    System.out.printf("Value: %s%s%s",
      snapshotElement.selectObject("Stats[@name='jvmRuntimeModule']/CS[@id='2']/@ct"),
      snapshotElement.selectObject("Stats[@name='systemModule']/CS[@id='1']/@ct"),
      snapshotElement.selectObject("Stats[@name='connectionPoolModule']/RS[@id='9']/@cur")
    ).println();
  System.out.println("*****************************************");
}

Dá se to optimalizovat, ty XPath výrazy se nemusí parsovat v každé iteraci cyklu, ale je možné si je vytvořit předem a v cyklu volat xpath1.evaluate(snapshotElement).

Pokud by ty XML soubory byly velké (stovky MB), stejně nedoporučuju používat SAX nebo StAX, protože jsou to zbytečně nízkoúrovňová API a to samé se dá zvládnout i s vysokoúrovňovými knihovnami. Např. s dom4j se dá použít ElementHandler:

Kód: [Vybrat]
SAXReader reader = new SAXReader();
reader.addHandler( "/TPVLog/Snapshot",
    new ElementHandler() {
        public void onStart(ElementPath path) {
            // Jsme na začátku elementu, neděláme nic
        }
        public void onEnd(ElementPath path) {
            Element snapshotElement = path.getCurrent();
            //Tady už máme zkonstruovaný strom pro element Snapshot, takže na něm můžeme zavolat úplně ten samý kód, jako v prvním příkladu:
            System.out.printf("Value: %s%s%s",
              snapshotElement.selectObject("Stats[@name='jvmRuntimeModule']/CS[@id='2']/@ct"),
              snapshotElement.selectObject("Stats[@name='systemModule']/CS[@id='1']/@ct"),
              snapshotElement.selectObject("Stats[@name='connectionPoolModule']/RS[@id='9']/@cur")
            ).println();
            System.out.println("*****************************************");

            //zpracovaný element odstraníme z dokumentu, aby zbytečně nezabíral místo
            snapshotElement .detach();
        }
    }
);

Document document = reader.read(url);
//z dokumentu zbyla jen obálka, ale to nevadí, můžeme ho zahodit

tdvorak

Re:Vytažení dat z XML v Javě
« Odpověď #13 kdy: 08. 04. 2015, 12:18:53 »
Aby tu nebylo těch variant málo, přihodím mou s jsoup knihovnou. Člověk pak může k datům přistupovat stejně, jako třeba v JQuery - pomocí CSS selectorů.

https://gist.github.com/todvora/490895c9e596e51f88d1


Dr.Who

Re:Vytažení dat z XML v Javě
« Odpověď #14 kdy: 13. 04. 2015, 14:30:31 »
Pro každý element Snapshot tedy chcete vypsat tu trojici?

Kód: [Vybrat]
Element root = document.getRootElement();
for (Element snapshotElement : (List<Element>) root.elements("Snapshot")) {
    System.out.printf("Value: %s%s%s",
      snapshotElement.selectObject("Stats[@name='jvmRuntimeModule']/CS[@id='2']/@ct"),
      snapshotElement.selectObject("Stats[@name='systemModule']/CS[@id='1']/@ct"),
      snapshotElement.selectObject("Stats[@name='connectionPoolModule']/RS[@id='9']/@cur")
    ).println();
  System.out.println("*****************************************");
}

Dá se to optimalizovat, ty XPath výrazy se nemusí parsovat v každé iteraci cyklu, ale je možné si je vytvořit předem a v cyklu volat xpath1.evaluate(snapshotElement).

Pokud by ty XML soubory byly velké (stovky MB), stejně nedoporučuju používat SAX nebo StAX, protože jsou to zbytečně nízkoúrovňová API a to samé se dá zvládnout i s vysokoúrovňovými knihovnami. Např. s dom4j se dá použít ElementHandler:

Kód: [Vybrat]
SAXReader reader = new SAXReader();
reader.addHandler( "/TPVLog/Snapshot",
    new ElementHandler() {
        public void onStart(ElementPath path) {
            // Jsme na začátku elementu, neděláme nic
        }
        public void onEnd(ElementPath path) {
            Element snapshotElement = path.getCurrent();
            //Tady už máme zkonstruovaný strom pro element Snapshot, takže na něm můžeme zavolat úplně ten samý kód, jako v prvním příkladu:
            System.out.printf("Value: %s%s%s",
              snapshotElement.selectObject("Stats[@name='jvmRuntimeModule']/CS[@id='2']/@ct"),
              snapshotElement.selectObject("Stats[@name='systemModule']/CS[@id='1']/@ct"),
              snapshotElement.selectObject("Stats[@name='connectionPoolModule']/RS[@id='9']/@cur")
            ).println();
            System.out.println("*****************************************");

            //zpracovaný element odstraníme z dokumentu, aby zbytečně nezabíral místo
            snapshotElement .detach();
        }
    }
);

Document document = reader.read(url);
//z dokumentu zbyla jen obálka, ale to nevadí, můžeme ho zahodit

Ano, presne tak. Zkusil sem pouzit tu prvni moznost

Element root = document.getRootElement();
for (Element snapshotElement : (List<Element>) root.elements("Snapshot")) {
    System.out.printf("Value: %s%s%s",
      snapshotElement.selectObject("Stats[@name='jvmRuntimeModule']/CS[@id='2']/@ct"),
      snapshotElement.selectObject("Stats[@name='systemModule']/CS[@id='1']/@ct"),
      snapshotElement.selectObject("Stats[@name='connectionPoolModule']/RS[@id='9']/@cur")
    ).println();
  System.out.println("*****************************************");
}
[/code]

prislo mi to nejjednodussi a vzhledem k mojim dovednostem Javy jako cesta nejmensiho odporu. Akorat na vystupu dostavam
pocet radku reprezentujici pocet nodu <stats> ale hodnoty, ktere se maji vytahnout jsou prazdne. Uz jsem zkousel i ruzne pomenit ty cesty, ale bez vysledku.

Co se XML tyce tak to je jeste cele ohranicene tagem TPVlog, zkousel sem si jeste hrat s tim, ze sem zmenil root elements na TPVLog ale bez uspechu.