简体   繁体   中英

How to fetch value from a custom XML with heterogeneous tags in Java?

I am having a custom XML like

<InputData>
    <dbproperties>
        <dburl>dbURL</dburl>
        <dbuser>DBUSER</dbuser>
        <dbpasskey>DBPASS</dbpasskey>
        <driver>oracle.jdbc.driver.OracleDriver</driver>    
    </dbproperties>
    <tdata>
        <size>4</tdata>    
        <tcount>6</tcount>
    </threaddata>
    <qdata>
        <sql>
            select syadate from dual;
        </sql>
    </qdata>
</InputData>

Now I need to read this XML and need tp fetch the values of each tag. Like

dburl = dbURL
dbuser = DBUSER
dbpasskey = DBPASS
driver = oracle.jdbc.driver.OracleDriver
size = 4
tcount = 6
sql = select syadate from dual;

How to do this in an efficient way, without hardcoding anything in the Java Class.

ie, I'll input the xml file name. The Java class should print the data output as above.

Step 1: Save your XML to a file (say "d:/test.xml") on your system.

<InputData>
    <dbproperties>
        <dburl>dbURL</dburl>
        <dbuser>DBUSER</dbuser>
        <dbpasskey>DBPASS</dbpasskey>
        <driver>oracle.jdbc.driver.OracleDriver</driver>    
    </dbproperties>
    <tdata>
        <size>4</size>    
        <tcount>6</tcount>
    </tdata>
    <qdata>
        <sql>
            select syadate from dual;
        </sql>
    </qdata>
</InputData>

Step 2: Now, create following class to run your program.

InputDataDemo.java

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

public class InputDataDemo {
    public static final String DB_URL = "dburl";
    public static final String DB_USER = "dbuser";
    public static final String DB_PASS_KEY = "dbpasskey";
    public static final String DRIVER = "driver";
    public static final String SIZE = "size";
    public static final String TCOUNT = "tcount";
    public static final String SQL = "sql";

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        File inputFile = new File("D:/test.xml");
        Map<String, String> map = getInputDataMap(new FileInputStream(inputFile));
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            System.out.println(key + ": " + map.get(key).trim());
        }
    }

    public static Map<String, String> getInputDataMap(InputStream inputStream)
            throws ParserConfigurationException, SAXException, IOException {

        Map<String, String> inputMap = new LinkedHashMap<String, String>();
        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream);
        doc.getDocumentElement().normalize();
        inputMap.put(DB_URL, ((Element) doc.getElementsByTagName(DB_URL).item(0)).getTextContent());
        inputMap.put(DB_USER, ((Element) doc.getElementsByTagName(DB_USER).item(0)).getTextContent());
        inputMap.put(DB_PASS_KEY, ((Element) doc.getElementsByTagName(DB_PASS_KEY).item(0)).getTextContent());
        inputMap.put(DRIVER, ((Element) doc.getElementsByTagName(DRIVER).item(0)).getTextContent());
        inputMap.put(SIZE, ((Element) doc.getElementsByTagName(SIZE).item(0)).getTextContent());
        inputMap.put(TCOUNT, ((Element) doc.getElementsByTagName(TCOUNT).item(0)).getTextContent());
        inputMap.put(SQL, ((Element) doc.getElementsByTagName(SQL).item(0)).getTextContent());
        return inputMap;
    }
}

If you don't exclude non-jaxb based solutions... here is a way of doing it with XPath and VTD-XML. The benefit of this is that you can literally put as many element/value pairs in to the file and it will still work... zero configuration...

import com.ximpleware.*;

public class dumpKeyValue {

    public static void main(String[] s) throws VTDException{
        VTDGen vg = new VTDGen();
        AutoPilot ap = new AutoPilot();
        ap.selectXPath("//*[text()]");
        if (!vg.parseFile("d:\\xml\\keyValue.xml", false)){
            System.out.println("invalid xml");
            System.exit(0);
        }
        VTDNav vn = vg.getNav();
        ap.bind(vn);
        int i=0;
        while((i=ap.evalXPath())!=-1){
            System.out.println(" "+vn.toRawString(i)+" = "+vn.toNormalizedString(vn.getText()));
        }
    }
}

If you're using Java 8, you could try using an XmlDynamic

XmlDynamic xml = new XmlDynamic("<InputData>" + // the xml
    "  <dbproperties>" +
    "    <dburl>dbURL</dburl>" +
    "    <dbuser>DBUSER</dbuser>" +
    "    <dbpasskey>DBPASS</dbpasskey>" +
    "    <driver>oracle.jdbc.driver.OracleDriver</driver>" +
    "  </dbproperties>" +
    "  <tdata>" +
    "    <size>4</size>    " +
    "    <tcount>6</tcount>" +
    "  </tdata>" +
    "  <qdata>" +
    "    <sql>select syadate from dual;</sql>" +
    "  </qdata>" +
    "</InputData>");

xml.get("InputData").children()
    .flatMap(Dynamic::children)
    .forEach(element -> System.out.println(element.key().asString() + " = " + element.asString()));

This will print out all depth-2 tag names (keys) and contents, ie in this case:

dburl = dbURL
dbuser = DBUSER
dbpasskey = DBPASS
driver = oracle.jdbc.driver.OracleDriver
size = 4
tcount = 6
sql = select syadate from dual;

See https://github.com/alexheretic/dynamics#xml-dynamics

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM