1

I need to Parse a JSON in java to a hash map. I tried a method by giving its tag name and attributes. While I need a generic version which will parse all attributes of the first child element of root element to a hash map.

I tried this code

public static void main() {
     Map<String, String> map = new HashMap<String, String>();
     String cfgXml = "<response><result code=\"0\" whatever=\"Whatever\"/></response>";
     try
        {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(new InputSource(new StringReader(cfgXml)));
            doc.getDocumentElement().normalize();
            System.out.println("Root element :" + doc.getDocumentElement().getNodeName());
            NodeList nList = doc.getElementsByTagName("result");
            System.out.println("----------------------------");
            for (int temp = 0; temp < nList.getLength(); temp++)
            {
                Node nNode = nList.item(temp);
                System.out.println("\nCurrent Element :" + nNode.getNodeName());
                if (nNode.getNodeType() == Node.ELEMENT_NODE)
                {
                    Element eElement = (Element) nNode;
                    Config c = new Config();
                    c.code = eElement.getAttribute("code");
                    c.whatever = eElement.getAttribute("whatever");
                    if(!map.containsKey(c.code)){
                        map.put("code", c.code);
                        map.put("whatever", c.whatever);
                    }
                    System.out.println(map);
                }
            }
            for (String name: map.keySet()){
                String key =name.toString();
                String value = map.get(name).toString();  
                /*** Key value will be output here **/
                System.out.println(key + "->" + value);  
            } 
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

public static class Config
{
    @Override
    public String toString()
    {
        return "Result [code=" + code + ", whatever=" + whatever + "]";
    }

    public String code;
    public String whatever;
}

Here I get the output, But here I am taking the tag name as result and attributes are also given. I need a generic function, I won't be knowing the tag name and attributes, It will be different in different XML string!

Any help will be appreciated

XML file can be :

<response>
        <balance balance=”1000000” overdraft=”0”/>
</response>

OR

<response>
<result code=”0”/>
</response>

It can change!!

3
  • I think i don't really understand what you're trying to do. Do you try to get all Attributes from a specific xml-element and store them in a map? If yes, what stops you from doing so? Commented Aug 2, 2017 at 10:40
  • @ParkerHalo An XML file will be given from an API. That XML file attributes may differ.. will not be same always. So I need a generic parsing method to get all attributes of the first child element of root element Commented Aug 2, 2017 at 10:53
  • the question states JSON... is it JSON or XML? Commented Aug 2, 2017 at 11:43

2 Answers 2

2

Consider this XML:

<root>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <!-- whatever -->
    </project>
</root>

In StAX it would be something like this (without the exception handling):

// your xml document
String xml;

BufferedReader br = new BufferedReader(new StringReader(xml));
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLStreamReader xmlReader = xif.createXMLStreamReader(br);

// stop reader in start root element
while (xmlReader.getEventType() != XMLStreamConstants.START_ELEMENT) {
    xmlReader.next();
}

// proceed
xmlReader.next();

// stop reader in the first child element
while (xmlReader.getEventType() != XMLStreamConstants.START_ELEMENT) {
    xmlReader.next();
}

// you can retrieve attributes
// with or without namespace and prefix information
for (int i = 0; i < xmlReader.getAttributeCount(); i++) {

    xmlReader.getAttributeLocalName(i); // schemaLocation
    xmlReader.getAttributeName(i);      // {http://www.w3.org/2001/XMLSchema-instance}schemaLocation
    xmlReader.getAttributeNamespace(i); // http://www.w3.org/2001/XMLSchema-instance
    xmlReader.getAttributePrefix(i);    // xsi
    xmlReader.getAttributeValue(i);     // http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd
}

xmlReader.close();
br.close();
Sign up to request clarification or add additional context in comments.

Comments

0

Here is an example using XPath 3.1 and Saxon 9.8 HE and the XPath expression map:merge(/*/*[1]/@*!map:entry(local-name(), data())) directly to create an XPath 3.1 map, you can then retrieve that as a Map<XdmAtomicValue, XdmValue> using Saxon's API and, if needed, convert it into a HashMap<String, String>:

    Processor proc = new Processor(false);
    XPathCompiler xpath = proc.newXPathCompiler();
    xpath.declareNamespace("map", "http://www.w3.org/2005/xpath-functions/map");

    DocumentBuilder builder = proc.newDocumentBuilder();

    XdmNode input = builder.build(new File(args.length > 0 ? args[0] : "input1.xml"));

    XPathSelector selector = xpath.compile("map:merge(/*/*[1]/@*!map:entry(local-name(), data()))").load();
    selector.setContextItem(input);

    XdmMap map = (XdmMap)selector.evaluateSingle();

    System.out.println(map);
    System.out.println(map.getClass().getName());

    Map<String, String> hashMap = new HashMap<String, String>();
    for (Entry<XdmAtomicValue, XdmValue> entry : map.entrySet())
    {
        hashMap.put(entry.getKey().getStringValue(), entry.getValue().toString());
    }

    System.out.println(hashMap);

Outputs e.g.

map{"overdraft":"0","balance":"1000000"}
net.sf.saxon.s9api.XdmMap
{balance=1000000, overdraft=0}

As an alternative, if you know you want a JSON string you could create the XPath 3.1 map as above but serialize it directly as JSON in XPath too:

        Processor proc = new Processor(false);
        XPathCompiler xpath = proc.newXPathCompiler();
        xpath.declareNamespace("map", "http://www.w3.org/2005/xpath-functions/map");

        DocumentBuilder builder = proc.newDocumentBuilder();

        XdmNode input = builder.build(new File(args.length > 0 ? args[0] : "input1.xml"));

        XPathSelector selector = xpath.compile("serialize(map:merge(/*/*[1]/@*!map:entry(local-name(), data())), map { 'method' : 'json' , 'indent' : true()})").load();
        selector.setContextItem(input);

        String json = selector.evaluateSingle().getStringValue();

        System.out.println(json);

Outputs e.g.

 {
  "overdraft":"0",
  "balance":"1000000"
 }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.