Link to home
Start Free TrialLog in
Avatar of tmricha
tmricha

asked on

Using JSP to read streaming XML, w/o tag libs

I am new to the JSP development world and have recently been asked to take on a project which I am not too familiar with.

What I need to do is this:
Grab/Call an xml stream via url (i.e. http://www.domain.com/xml/opentickets.xml)

This returns a valid XML document of the structure: (real example of output)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE  HDTickets [
<!ELEMENT Ticket (ticketID, title,status, owner, creationTime)>
<!ELEMENT ticketID (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT status (#PCDATA)>
<!ELEMENT owner (#PCDATA)>
<!ELEMENT creationTime (#PCDATA)>
]>
<HDTickets>
<Ticket ticketID="030625_1317672"
title ="EAP Not Working From outside."
status ="Pending - User Delay"
owner ="e_operations"
creationTime ="2003-06-25 10:29:31">
 </Ticket>
<Ticket ticketID="040414_1339696"
title ="Shared Mailbox Creation"
status ="Solving"
owner ="clarify"
creationTime ="2004-04-14 08:26:58">
 </Ticket>
<Ticket ticketID="040414_1339697"
title ="Other(Act)"
status ="Solving"
owner ="clarify"
creationTime ="2004-04-14 16:28:16">
 </Ticket>
 </HDTickets>


Using JSP, I would like to be able to read the values of each ticket(ticketid, title, status, owner, creationtime), assigne them to a variable, and then display them on the page as pure text
( out.println="Ticket ID= " & varTicketID )

I have no control over the format of the XML coming back, nor do I have ownership over the server to install any special software.

I figure there has to be a way that JSP can read this, asign data to variables, and then display....

The problem is, I really have no idea where to begin, and most sites I have been able to find discuss using specific parsers, installs, etc.

PLEASE HELP ME :)
Avatar of john-at-7fff
john-at-7fff

Right -- Shortly I'll paste in a good DTD for the attributes version, and also some sample code for when it's elements (your code is close, but not quite).
This is a job for XSL. You can write an XSL stylesheet to transform the XML into HTML, or just text. The XSL stylesheet's essential elements would be something like this:

<xsl:stylesheet ...>
  <xsl:output method="text" omit-xml-declaration="true"/>
  <xsl:template match="Ticket">TicketID=<xsl:value-of select="@ticketID"/></xsl:template>
</xsl:stylesheet>

You may need to tweak that a little but that's basically it. You could also switch this to generate HTML if desired. Here is a good place to learn about XSL: http://www.w3schools.com/xsl/


If you are able to use the JSTL tags in your JSP application, then it can make this task easy. You would be able to generate the text you want in your JSP with a tag like this:

<c:import url="http://www.domain.com/xml/opentickets.xml" var="theXML"/>
<x:transform xslt="*the text of your stylesheet*" doc="${theXML}"/>

I haven't tested it but I think that's basically right.

You can find out more about JSTL here: java.sun.com/products/jsp/jstl/
This is a good JSTL reference sheet: http://www.jadecove.com/jstl-quick-reference.pdf

If this approach is viable then I think it is the cleanest way to go. No coding needed.
OK. First off, here's a DTD embedded in the XML that actually matches the data you're getting. Your offshore guys are just way off. Then I've pasted in some code that is exactly like what I gave you before, except that it requests a "validating parser." This should work fine on your server as well -- try it. I've put a comment with a lot of stars next to the line that is changed for validation.

Now, if you validate, you normally would create a special error handling that would, say, dump error information to the server console. For that, you're getting into real Java code for dealing with XML -- at that point, you should start reading up on Java, XML, JSP, more generally.

Next I'll post something that would work if they changed the feed to use elements instead of attributes.

seanrowan's post above is very similar to my original JSTL suggestion. But since you can't easily deploy the JSTL jars, a pure JSP solution is probably good for now.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE HDTickets [
<!ELEMENT HDTickets (Ticket)*>
<!ELEMENT Ticket (#PCDATA)>
<!ATTLIST Ticket
      ticketID     CDATA #REQUIRED
      title        CDATA #REQUIRED
      status       CDATA #REQUIRED
      owner        CDATA #REQUIRED
      creationTime CDATA #REQUIRED>
]>
<HDTickets>
<Ticket ticketID="030625_1317672"
title ="EAP Not Working From outside."
status ="Pending - User Delay"
owner ="e_operations"
creationTime ="2003-06-25 10:29:31"/>
<Ticket ticketID="040414_1339696"
title ="Shared Mailbox Creation"
status ="Solving"
owner ="clarify"
creationTime ="2004-04-14 08:26:58">
</Ticket>
<Ticket ticketID="040414_1339697"
title ="Other(Act)"
status ="Solving"
owner ="clarify"
creationTime ="2004-04-14 16:28:16">
</Ticket>
</HDTickets>


I've posted this at http://7fff.com/tickets3.xml



Here's the JSP:



<%@ page import="java.io.IOException" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="javax.xml.parsers.DocumentBuilder" %>
<%@ page import="javax.xml.parsers.DocumentBuilderFactory" %>
<%@ page import="javax.xml.parsers.ParserConfigurationException" %>
<%@ page import="org.w3c.dom.Document" %>
<%@ page import="org.w3c.dom.Element" %>
<%@ page import="org.w3c.dom.NodeList" %>
<%@ page import="org.xml.sax.SAXException" %>

<%
ArrayList exceptionList = new ArrayList();
ArrayList ticketIDs = new ArrayList();
DocumentBuilder parser = null;
Document d = null;

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true);      // ***** Now parser validates according to embedded DTD *****
try {
      parser = dbf.newDocumentBuilder();
      d = parser.parse("http://7fff.com/tickets3.xml");
} catch (ParserConfigurationException e) {
      e.printStackTrace();
} catch (SAXException e) {
      e.printStackTrace();
} catch (IOException e) {
      e.printStackTrace();
}

if (d != null) {
      NodeList tickets = d.getElementsByTagName("Ticket");
      for (int i = 0; i < tickets.getLength(); i++) {
            Element e = (Element) tickets.item(i);
            ticketIDs.add(e.getAttribute("ticketID").toString());
      }
}
%>
<html>
<body>
<%

if (exceptionList.size() != 0) {
      out.println("The following exceptions were encountered: <br>");
      for (int i = 0; i < exceptionList.size(); i++)
            out.println("<li> " + exceptionList.get(i));
}

out.println("Number of Tickets found: " + ticketIDs.size());
out.println("<p>");

out.print("Ticket IDs: <br>");
for (int i = 0; i < ticketIDs.size(); i++)
      out.println("<li> " + ticketIDs.get(i));
%>
</body>
</html>
Alright, here's the "elements" version of the XML with the embedded DTD (see http://7fff.com/tickets2.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE HDTickets [
<!ELEMENT HDTickets (Ticket)*>
<!ELEMENT Ticket (ticketID, title,status, owner, creationTime)>
<!ELEMENT ticketID (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT status (#PCDATA)>
<!ELEMENT owner (#PCDATA)>
<!ELEMENT creationTime (#PCDATA)>
]>
<HDTickets>
 <Ticket>
  <ticketID>030625_1317672</ticketID>
  <title>EAP Not Working From outside.</title>
  <status>Pending - User Delay</status>
  <owner>e_operations</owner>
  <creationTime>2003-06-25 10:29:31</creationTime>
 </Ticket>
 <Ticket>
  <ticketID>040414_1339697</ticketID>
  <title>Other(Act)</title>
  <status>Solving</status>
  <owner>clarify</owner>
  <creationTime>2004-04-14 16:28:16</creationTime>
 </Ticket>
</HDTickets>

And here's the code. To understand how the DOM is being traversed, you'll need to read up on it. As you move along with your Java/JSP knowledge, you would want to take a lot of this parsing code and put it in a real Java class. Then have the JSP call that class. Or, as I said in the earlier post, if you can upgrade your server to use JSP 1.2, you could use JSTL and have virtually no Java code -- which would be much easier to maintain.

<%@ page import="java.io.IOException" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="javax.xml.parsers.DocumentBuilder" %>
<%@ page import="javax.xml.parsers.DocumentBuilderFactory" %>
<%@ page import="javax.xml.parsers.ParserConfigurationException" %>
<%@ page import="org.w3c.dom.Document" %>
<%@ page import="org.w3c.dom.Element" %>
<%@ page import="org.w3c.dom.NodeList" %>
<%@ page import="org.w3c.dom.Node" %>
<%@ page import="org.xml.sax.SAXException" %>

<%
ArrayList exceptionList = new ArrayList();
ArrayList ticketIDs = new ArrayList();
ArrayList titles = new ArrayList();
DocumentBuilder parser = null;
Document d = null;

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true);      // ***** Now parser validates according to embedded DTD *****
dbf.setIgnoringElementContentWhitespace(true);      // ***** Very important to simplify parsing *****
try {
      parser = dbf.newDocumentBuilder();
      d = parser.parse("http://7fff.com/tickets2.xml");
} catch (ParserConfigurationException e) {
      e.printStackTrace();
} catch (SAXException e) {
      e.printStackTrace();
} catch (IOException e) {
      e.printStackTrace();
}

if (d != null) {
      NodeList tickets = d.getElementsByTagName("Ticket");
      for (int i = 0; i < tickets.getLength(); i++) {
            Node ticketNode = tickets.item(i);
            NodeList ticketElements = ticketNode.getChildNodes();

            NodeList children;
            String val;
                              
            // Deal with the ticketID
            Node ticketIDNode = ticketElements.item(0);
            children = ticketIDNode.getChildNodes();
            val = "";
            if (children.getLength() != 0)
                  val = children.item(0).getNodeValue();
            ticketIDs.add(val);

            // Deal with the title
            Node titleIDNode = ticketElements.item(1);
            children = titleIDNode.getChildNodes();
            val = "";
            if (children.getLength() != 0)
                  val = children.item(0).getNodeValue();
            titles.add(val);
      }
}
%>
<html>
<body>
<%

if (exceptionList.size() != 0) {
      out.println("The following exceptions were encountered: <br>");
      for (int i = 0; i < exceptionList.size(); i++)
            out.println("<li> " + exceptionList.get(i));
}

out.println("Number of Tickets found: " + ticketIDs.size());
out.println("<p>");

out.print("Ticket ID: title <br>");
for (int i = 0; i < ticketIDs.size(); i++)
      out.println("<li> " + ticketIDs.get(i) + ": '" + titles.get(i) + "'");
%>
</body>
</html>
Avatar of tmricha

ASKER

One final request. I have a string that returns date and time (example: "2004-04-14 16:29:41").
I just want the date portion. How do I split this up.

I know in VB I search for the position of the [space], and then trim the string to that length.  But I dont know the search-for position command in jsp.

Thanks again!
ASKER CERTIFIED SOLUTION
Avatar of john-at-7fff
john-at-7fff

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Here's another way to do it that will work on JDKs prior to 1.4, if that helps too. It may be marginally faster.

String yourString = "2004-04-14 16:29:41";
String datePortion = yourString.substring(0, yourString.indexOf(' '));