I am trying to integrate a Usurv survey to my website. To do this, I need to submit an XML request to the URL http://app.usurv.com/API/Gateway.svc/getcampaignforframe, using HTTP POST. Then the response should contain a unique URL pointing to a survey.
Unfortunately I can't get it to work - the code compiles correctly but when I load the webpage I get the following exception:
"WARNING: URL = http://app.usurv.com/API/Gateway.svc/getcampaignforframe
[Fatal Error] CampaignFrameRequest%3E:6:3: The element type "link" must be terminated by the matching end-tag "</link>"."
I'm really confused about that as the XML doesn't even have a link
tag, so I'm not sure where the error could be coming from. Does anyone have any ideas what could be causing this and how I can fix it?
Here is the Java code:
public class UsurvSurveyElement extends RenderController
{
private static Logger LOG = Logger.getLogger(UsurvSurveyElement.class.getName());
String xml = "<CampaignFrameRequest xmlns='http://Qsurv/api' xmlns:i='http://www.w3.org/2001/XMLSchema-instance'><PartnerId>236</PartnerId><PartnerWebsiteID>45</PartnerWebsiteID><RespondentID>1</RespondentID><RedirectUrlComplete>http://localhost:8080/eveningstar/home</RedirectUrlComplete><RedirectUrlSkip>http://localhost:8080/eveningstar/home</RedirectUrlSkip></CampaignFrameRequest>";
String strURL = "http://app.usurv.com/API/Gateway.svc/getcampaignforframe";
#Override
public void populateModelBeforeCacheKey(RenderRequest renderRequest, TopModel topModel, ControllerContext controllerContext )
{
super.populateModelBeforeCacheKey( renderRequest, topModel, controllerContext );
PostMethod post = new PostMethod(strURL);
try
{
// Specify content type and encoding
// If content encoding is not explicitly specified
// ISO-8859-1 is assumed
post.setRequestHeader(
"Content-type", "text/xml; charset=ISO-8859-1");
LOG.warning("request headers: " +post.getRequestHeader("Content-type"));
StringRequestEntity requestEntity = new StringRequestEntity(xml);
post.setRequestEntity(requestEntity);
LOG.warning("request entity: " +post.getRequestEntity());
String response = post.getResponseBodyAsString();
LOG.warning("XML string = " + xml);
LOG.warning("URL = " + strURL);
topModel.getLocal().setAttribute("thexmlresponse",response);
}
catch(Exception e)
{
LOG.warning("Errors while executing postMethod "+ e);
}
try
{
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document document = docBuilder.parse(strURL+xml);
processNode(document.getDocumentElement());
LOG.warning("doc output = " + document);
}
catch(Exception e)
{
LOG.warning("Errors while parsing XML: "+ e);
}
}
private void processNode(Node node) {
// do something with the current node instead of System.out
LOG.warning(node.getNodeName());
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node currentNode = nodeList.item(i);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
//calls this method for all the children which is Element
LOG.warning("current node: " + currentNode);
processNode(currentNode);
}
}
}
}
This line looks really strange, don't you mean to parse the response body instead?
Document document = docBuilder.parse(strURL+xml);
The parse method with a string parameter uses this string as an URL, so the XML parser is connection to the server again, using a GET request. The server is probably responding with an error message in HTML format, leading to the exception complaining about the link element.
Something like the following should work better:
Document document = docBuilder.parse(new InputSource(new StringReader(response)));
Related
I am parsing XML from lots of JMS messaging topics, so the structure of each message varies a lot and I'd like to make one general tool to parse them all.
To start, all I want to do is get the element names:
<gui-action>
<action>some action</action>
<params>
<param1>blue</param1>
<param2>tall</param2>
<params>
</gui-action>
I just want to retrieve the strings "gui-action", "action", "params", "param1", and "param2." Duplicates are just fine.
I've tried using org.w3c.dom.Node, Element, NodeLists and I'm not having much luck. I keep getting the element values, not the names.
private Element root;
private Document doc;
private NodeList nl;
//messageStr is passed in elsewhere in the code
//but is a string of the full XML message.
doc = xmlParse( messageStr );
root = doc.getDocumentElement();
nl = root.getChildNodes();
int size = nl.getLength();
for (int i=0; i<size; i++) {
log.info( nl.item(i).getNodeName() );
}
public Document xmlParse( String xml ){
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
InputSource is;
try {
//Using factory get an instance of document builder
db = dbf.newDocumentBuilder();
is = new InputSource(new StringReader( xml ) );
doc = db.parse( is );
} catch(ParserConfigurationException pce) {
pce.printStackTrace();
} catch(SAXException se) {
se.printStackTrace();
} catch(IOException ioe) {
ioe.printStackTrace();
}
return doc;
//parse using builder to get DOM representation of the XML file
}
My logged "parsed" XML looks like this:
#text
action
#text
params
#text
Figured it out. I was iterating over only the child nodes, and not including the parent. So now I just filter out the #texts, and include the parent. Derp.
log.info(root.getNodeName() );
for (int i=0; i<size; i++) {
nodeName = nl.item(i).getNodeName();
if( nodeName != "#text" ) {
log.info( nodeName );
}
}
Now if anyone knows a way to get a NodeList of the entire document, that would be awesome.
I looked over several of the answers posted here, but I can't find the answer I need. It may have to do with the web site itself, but I don't think it is.
I'm trying to parse an XML on a web site and I'm getting a null pointer exception error.
I run the parsing is a separate thread following Google demand when reading from the web.
please see my code and try to help.
class BackgroundTask1 extends AsyncTask<String, Void, String[]> {
protected String[] doInBackground(String... url) {
new HttpGet();
new StringBuffer();
InputStream is = null;
HttpURLConnection con = null;
try {
//Log.d("eyal", "URL: " + boiUrl);
URL url1 = new URL("http://www.boi.org.il/currency.xml");
con = (HttpURLConnection)url1.openConnection();
con.setRequestMethod("GET");
con.connect();
is = con.getInputStream();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(is);
NodeList lastVld = doc.getElementsByTagName("LAST_UPDATE");
String lastV = lastVld.item(0).getFirstChild().getNodeValue();
}
catch (Exception e) {
e.printStackTrace();
}
I get the error on the last line.
Thanks for your help.
This code worked for me
InputStream is = null;
HttpURLConnection con = null;
try {
URL url1 = new URL("http://www.boi.org.il/currency.xml");
con = (HttpURLConnection)url1.openConnection();
con.setRequestMethod("GET");
con.connect();
is = con.getInputStream();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(is);
NodeList lastVld = doc.getElementsByTagName("LAST_UPDATE");
Element elem = (Element) lastVld.item(0);
String lastV = elem.getTextContent();
System.out.println(lastV);
} catch (Exception e) {
e.printStackTrace();
}
I verified I was getting good content by adding a transformer to print out the results to the console.
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer xform = tFactory.newTransformer();
xform.transform(new DOMSource(doc), new StreamResult(System.out));
There was a couple times I tried running where elem came out null, which I think had something to do with some bad content being retrieved from the URL. This was the content that was printed by the transformer.
<html>
<body>
<script>document.cookie='iiiiiii=11a887d6iiiiiii_11a887d6; path=/';window.location.href=window.location.href;</script>
</body>
</html>
I noticed that if I had this file open in my browser, the code would all of a sudden quit working until I refreshed the page, then it started giving me the right output.
I suspect there's an issue with something at this URL, because when it works properly, this code works fine.
Good luck...
You only have one LAST_UPDATE tag in your xml and it has an inner value, so try just using the node value from the Node Class you get from item(0)
String lastV = lastVld.item(0).getNodeValue();
HTHs
There is no node returned for that tag name. You may want to first check the size of the lastVld and then try to access the items in there.
I use Wikimedia API Sandbox for Japanese.
Japanese Version
English Version
I send a HTTP request to Wikimedia and I get a result formed in XML.
When I try to send a request and get a result on API Sandbox Webpage, there is no character corruption in a result.
But when I get a result in Java, a result includes character corruptions.
I cannot assign a specific character code in XML file.
How can I assign a result a specific character code?
How can I resolve my problem?
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db
.parse(new URL(
"http://ja.wikipedia.org/w/api.php?action=query&prop=categories&format=xml&cllimit=10&titles="
+ key).openStream());
Element root = doc.getDocumentElement();
NodeList queryList = root.getChildNodes();
Node query = queryList.item(0);
if (query instanceof Element) {
Element queryEle = (Element) query;
NodeList pagesList = queryEle.getChildNodes();
Node pgs = pagesList.item(0);
if (pgs instanceof Element) {
Element pagesElement = (Element) pgs;
NodeList pageList = pagesElement.getChildNodes();
Node page = pageList.item(0);
if (page instanceof Element) {
Element pageElement = (Element) page;
String title = pageElement.getAttribute("title");
title = new String(title.getBytes("UTF-8"), "UTF-8");
}
}
}
} catch (ParserConfigurationException e) {
} catch (SAXException e) {
} catch (IOException e) {
}
Now I send a request, I got a result whose page title is "大学". But in Java, it shows "??".
I use above code for Android Application.
title = new String(title.getBytes("UTF-8"), "UTF-8"); can be left out.
It worked for me, for key=1 (receiving UTF-8). I have a UTF-8 Linux PC though. Maybe you did not output in a UTF-8 context or so. Try write the Document to a file.
You could do more inspection:
URLConnection connection = new URL("...").openConnection();
... connection.getContentEncoding();
... connection.getContentType();
InputStream in = connection.openStream();
I am doing conversion from XHTML to PDF using flying saucer, it works perfectly but now i want to add bookmarks, and according to the fs documentation it should be done like this:
<bookmarks>
<bookmark name='1. Foo bar baz' href='#1'>
<bookmark name='1.1 Baz quux' href='#1.2'>
</bookmark>
</bookmark>
<bookmark name='2. Foo bar baz' href='#2'>
<bookmark name='2.1 Baz quux' href='#2.2'>
</bookmark>
</bookmark>
</bookmarks>
That should be put into the HEAD section, I have done that but the SAXParser wont read the file anymore, saying:
line 11 column 14 - Error: <bookmarks> is not recognized!
line 11 column 25 - Error: <bookmark> is not recognized!
I have a local entity resolver set up and have even added the bookmarks to a DTD,
<!--flying saucer bookmarks -->
<!ELEMENT bookmarks (#PCDATA)>
<!ATTLIST bookmarks %attrs;>
<!ELEMENT bookmark (#PCDATA)>
<!ATTLIST bookmark %attrs;>
But it just wont parse, I am out of ideas, please help.
EDIT
I am using the following code to parse:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
builder.setEntityResolver(new LocalEntityResolver());
document = builder.parse(is);
EDIT
Here is LocalEntityResolver:
class LocalEntityResolver implements EntityResolver {
private static final Logger LOG = ESAPI.getLogger(LocalEntityResolver.class);
private static final Map<String, String> DTDS;
static {
DTDS = new HashMap<String, String>();
DTDS.put("-//W3C//DTD XHTML 1.0 Strict//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
DTDS.put("-//W3C//DTD XHTML 1.0 Transitional//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
DTDS.put("-//W3C//ENTITIES Latin 1 for XHTML//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent");
DTDS.put("-//W3C//ENTITIES Symbols for XHTML//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent");
DTDS.put("-//W3C//ENTITIES Special for XHTML//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent");
}
#Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
InputSource input_source = null;
if (publicId != null && DTDS.containsKey(publicId)) {
LOG.debug(Logger.EVENT_SUCCESS, "Looking for local copy of [" + publicId + "]");
final String dtd_system_id = DTDS.get(publicId);
final String file_name = dtd_system_id.substring(
dtd_system_id.lastIndexOf('/') + 1, dtd_system_id.length());
InputStream input_stream = FileUtil.readStreamFromClasspath(
file_name, "my/class/path",
getClass().getClassLoader());
if (input_stream != null) {
LOG.debug(Logger.EVENT_SUCCESS, "Found local file [" + file_name + "]!");
input_source = new InputSource(input_stream);
}
}
return input_source;
}
}
My document builder factory implementation is :
com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
Ugh, I finally found the problem. Sorry for making you guys debug the code, the problem was that in my code there was a call to JTidy.parse just before the DOM parsing occurred, this resulted in the content to be parsed to be empty and i did not even catch that, the actual Error was, Premature End of file from SAX.
Thanks to Matt Gibson, while i was going through the code to compile a short input document, i found the bug.
My code now includes a check to see if the content was null
/**
* parses String content into a valid XML document.
* #param content the content to be parsed.
* #return the parsed document or <tt>null</tt>
*/
private static Document parse(final String content) {
Document document = null;
try {
if (StringUtil.isNull(content)) {
throw new IllegalArgumentException("cannot parse null "
+ "content into a DOM object!");
}
InputStream is = new ByteArrayInputStream(content
.getBytes(CONTEXT.getEncoding()));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
builder.setEntityResolver(new LocalEntityResolver());
document = builder.parse(is);
} catch (Exception ex) {
LOG.error(Logger.EVENT_FAILURE, "parsing failed "
+ "for content[" + content + "]", ex);
}
return document;
}
I am trying to send an XML file to my RESTful web server, and receive a XML file in return, however, I am getting a 500 error.
java.io.IOException: Server returned HTTP response code: 500 for URL:
http://sps-psa-240:8080/NMCJWS/rest/jmsmon2/pub at
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1436)
at SendXML.send(SendXML.java:151)
at SendXML.main(SendXML.java:39)
Line 151 is InputStream response = uc.getInputStream();
If I uncomment System.out.println(((HttpURLConnection) uc).getResponseCode());,
then I get the same error on OutputStreamWriter out = new OutputStreamWriter(uc.getOutputStream());
I know the server works because a coworker has this working in Obj-C.
Here is my code:
public class SendXML
{
public static void main(String[] args) throws SAXException, XPathExpressionException, ParserConfigurationException,
IOException, TransformerException
{
String xml = generateXML("AC24", "/fa/gdscc/dss24-apc");
send("localhost", xml);
}
public static String generateXML(String conn, String funcAddr) throws ParserConfigurationException, SAXException,
IOException, XPathExpressionException, TransformerException
{
/*
* <?xml version="1.0" encoding="UTF-8"?>
<JMSMON2Req>
<SubItem UID="iPAD-2031e616-de74-44a7-9292-3745d2b1ba21">
<FuncAddr>/fa/gdscc/con1-ac25</FuncAddr>
<ItemName>AZANG</ItemName>
<ItemName>ELANG</ItemName>
<Metadata key="UID">iPAD-2031e616-de74-44a7-9292-3745d2b1ba21</Metadata>
<Metadata key="CONN">1</Metadata>
</SubItem>
</JMSMON2Req>
*/
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("http://sps-psa-240:8080/NMCWS/rest/conn/subsys/prof?ss=" + conn + "&pt=IPAD_DASHBOARD");
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile("/SubscrProf/DataItem/DataItemName");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
//build xml
Document output = builder.newDocument();
//create root
org.w3c.dom.Element root = output.createElement("JMSMON2Req");
output.appendChild(root);
//create subitem
org.w3c.dom.Element subItemNode = output.createElement("SubItem");
subItemNode.setAttribute("UID", "IPAD-CN1-DSS26-SC151-PN230-AC26");
root.appendChild(subItemNode);
//create funcAddr
org.w3c.dom.Element funcAddrNode = output.createElement("FuncAddr");
Text text = output.createTextNode(funcAddr);
funcAddrNode.appendChild(text);
subItemNode.appendChild(funcAddrNode);
//create itemname
for (int i = 0; i < nodes.getLength(); i++)
{
org.w3c.dom.Element itemNameNode = output.createElement("SubItem");
text = output.createTextNode(nodes.item(i).getTextContent());
itemNameNode.appendChild(text);
subItemNode.appendChild(itemNameNode);
}
//create metadata uid
org.w3c.dom.Element metaDataNode = output.createElement("Metadata");
metaDataNode.setAttribute("key", "UID");
text = output.createTextNode("IPAD-CN1-DSS26-SC151-PN230-AC26");
metaDataNode.appendChild(text);
subItemNode.appendChild(metaDataNode);
//create metadata conn
org.w3c.dom.Element metaDataNode2 = output.createElement("Metadata");
metaDataNode2.setAttribute("key", "CONN");
text = output.createTextNode("4");
metaDataNode2.appendChild(text);
subItemNode.appendChild(metaDataNode2);
/////////////////
//Output the XML
//set up a transformer
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer trans = transfac.newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
//create string from xml tree
StringWriter sw = new StringWriter();
StreamResult out = new StreamResult(sw);
DOMSource source = new DOMSource(output);
trans.transform(source, out);
String xmlString = sw.toString();
//print xml
System.out.println("Here's the xml:\n" + xmlString);
return xmlString;
}
public static void send(String urladdress, String file) throws MalformedURLException, IOException
{
String charset = "UTF-8";
String s = URLEncoder.encode(file, charset);
// Open the connection and prepare to POST
URLConnection uc = new URL(urladdress).openConnection();
uc.setDoOutput(true);
uc.setRequestProperty("Accept-Charset", charset);
uc.setRequestProperty("Content-Type","text/xml");
try
{
//System.out.println(((HttpURLConnection) uc).getResponseCode());
OutputStreamWriter out = new OutputStreamWriter(uc.getOutputStream());
out.write(s);
out.flush();
InputStream response = uc.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(response));
String line;
while ((line = r.readLine()) != null)
System.out.println(line);
out.close();
response.close();
}
catch (IOException e)
{
e.printStackTrace(); // should do real exception handling
}
}
}
I figured out my problem. I had to encode xmlString in UTF-8
Look at the logs on the server. What is causing the 500 error?
Is this a RESTful web service, or a SOAP web service you're submitting to?
Consider using some sort of XML<->Object framework like JAXB or XStream.
Consider using some sort of RESTful web service framework like Jersey or RestEasy.
Consider using some sort of SOAP framework like JAX-WS or Apache Axis
Make sure you are using the right encoding.
URLEncoder.encode is making the content safe for transfer as 'application/x-www-form-urlencoded', but you probably want to use UTF-8.
Also, new OutputStreamWriter(...) should specify the desired encoding. You are currently using the standard platform encoding which is probably iso-8859-1.
Third, don't try to mess around with URLConnection yourself, if there are plenty of libs around there, that can make you life easier.
Here is the send method done in Resty (Disclaimer: I'm the author of it). HTTPClient is another choice to consider as are other client-side libraries.
import us.monoid.web.Resty;
import static us.monoid.web.Resty.*;
Resty r = new Resty();
String result = r.text(urladdress, new Content("text/xml", file.getBytes("UTF-8"))).toString();