4

I want to get nodes from an api which contains xml elements.

https://www.w3schools.com/xml/cd_catalog.xml Here is the link for the api.

So my Java code is like this:

    package in.automationtesting.neh;
    
    import java.io.IOException;
    import java.io.Reader;
    import java.io.StringReader;
    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.xpath.XPath;
    import javax.xml.xpath.XPathConstants;
    import javax.xml.xpath.XPathExpression;
    import javax.xml.xpath.XPathExpressionException;
    import javax.xml.xpath.XPathFactory;
    
    import org.w3c.dom.Document;
    import org.w3c.dom.NodeList;
    import org.xml.sax.InputSource;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    public class Test1 {
        
        
    
            public static final String GET_API_URL = "https://www.w3schools.com/xml/cd_catalog.xml";        
            
            public static void main(String[] args) throws IOException, InterruptedException {
                HttpClient client = HttpClient.newHttpClient();
                HttpRequest request = HttpRequest.newBuilder()
                        .GET()
                        .header("accept", "application/xml")
                        .uri(URI.create(GET_API_URL))
                        .build();
                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                 
        
                 XPathFactory xpathfactory = XPathFactory.newInstance();
                 XPath xpath = xpathfactory.newXPath();
                 
                try {
    
                    Reader reader = new StringReader(response.body());
                    InputSource inputSource = new InputSource(reader);
                    XPath xpath1 = XPathFactory.newInstance().newXPath();
                    System.out.println(xpath1.evaluate("//CATALOG/CD", inputSource));
                    
                } catch (XPathExpressionException e) {
                    
                    e.printStackTrace();
                }

            }
}

The output on the console should be like this:

<CATALOG>
<CD>
<TITLE>1999 Grammy Nominees</TITLE>
<ARTIST>Many</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Grammy</COMPANY>
<PRICE>10.20</PRICE>
<YEAR>1999</YEAR>
</CD>


<CD>
<TITLE>Big Willie style</TITLE>
<ARTIST>Will Smith</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1997</YEAR>
</CD>
</CATALOG>

With the xpath expression i want to get the cd's which are released from 1995 and later ,plus they should be only from USA. And when i only match the root in the xpath expression which is CATALOG it shows all the elements which is good, but when i add cd next to it, on the console it only shows one album and not all of them, idk why i tried something like this in the expression and other varieties of it but no luck "//CATALOG/CD[@year>1995 and country='USA']

UchihaMalo
  • 75
  • 5

2 Answers2

3

You have to use a NodeList with XPathConstants.NODESET

Your expression is /CATALOG/CD[COUNTRY='USA' and YEAR>=1985] (The "@" is for attributes)

The syntax is:

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class Test1 {

    public static final String GET_API_URL = "https://www.w3schools.com/xml/cd_catalog.xml";

    public static void main(String[] args) throws IOException, InterruptedException {

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder().GET().header("accept", "application/xml").uri(URI.create(GET_API_URL)).build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        try {
            Reader reader = new StringReader(response.body());
            InputSource inputSource = new InputSource(reader);

            XPath xpath = XPathFactory.newInstance().newXPath();
            XPathExpression expr = xpath.compile("/CATALOG/CD[COUNTRY='USA' and YEAR>=1985]");
            NodeList list = (NodeList)expr.evaluate(inputSource, XPathConstants.NODESET);
            
            for (int i = 0; i < list.getLength(); i++) {
                Node node = list.item(i);
                System.out.println(node.getTextContent());
            }
        }
        catch (XPathExpressionException e) {
            e.printStackTrace();
        }
    }
}

That gives:

Empire Burlesque
Bob Dylan
USA
Columbia
10.90
1985


When a man loves a woman
Percy Sledge
USA
Atlantic
8.70
1987


1999 Grammy Nominees
Many
USA
Grammy
10.20
1999


Big Willie style
Will Smith
USA
Columbia
9.90
1997


Unchain my heart
Joe Cocker
USA
EMI
8.20
1987
Stéphane Millien
  • 3,238
  • 22
  • 36
3

This other solution uses a Transformer to format the output.

I found this solution here and here.

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class Test1 {

    public static final String GET_API_URL = "https://www.w3schools.com/xml/cd_catalog.xml";

    public static void main(String[] args) throws IOException, InterruptedException {

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder().GET().header("accept", "application/xml").uri(URI.create(GET_API_URL)).build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        try {
            Reader reader = new StringReader(response.body());
            InputSource inputSource = new InputSource(reader);

            XPath xpath = XPathFactory.newInstance().newXPath();
            XPathExpression expr = xpath.compile("/CATALOG/CD[COUNTRY='USA' and YEAR>=1985]");
            NodeList list = (NodeList)expr.evaluate(inputSource, XPathConstants.NODESET);

            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            
            for (int i = 0; i < list.getLength(); i++) {
                StringWriter writer = new StringWriter();
                transformer.transform(new DOMSource(list.item(i)), new StreamResult(writer));
                System.out.println(writer.toString());
            }
        }
        catch (XPathExpressionException | TransformerException e) {
            e.printStackTrace();
        }
    }
}

The result is now:

<CD>
    <TITLE>Empire Burlesque</TITLE>
    <ARTIST>Bob Dylan</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>Columbia</COMPANY>
    <PRICE>10.90</PRICE>
    <YEAR>1985</YEAR>
  </CD>
<CD>
    <TITLE>When a man loves a woman</TITLE>
    <ARTIST>Percy Sledge</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>Atlantic</COMPANY>
    <PRICE>8.70</PRICE>
    <YEAR>1987</YEAR>
  </CD>
<CD>
    <TITLE>1999 Grammy Nominees</TITLE>
    <ARTIST>Many</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>Grammy</COMPANY>
    <PRICE>10.20</PRICE>
    <YEAR>1999</YEAR>
  </CD>
<CD>
    <TITLE>Big Willie style</TITLE>
    <ARTIST>Will Smith</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>Columbia</COMPANY>
    <PRICE>9.90</PRICE>
    <YEAR>1997</YEAR>
  </CD>
<CD>
    <TITLE>Unchain my heart</TITLE>
    <ARTIST>Joe Cocker</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>EMI</COMPANY>
    <PRICE>8.20</PRICE>
    <YEAR>1987</YEAR>
  </CD>
Stéphane Millien
  • 3,238
  • 22
  • 36