Why did qName work and LocalName did not? - java

I was learning the Java SAX API. I made my own XML feed using php. Here is the XML Document
Now when i wanted to make my application output to the console nothing came up. I pinpointed the problem to the endElement method in my XMLHandler that extends DefaultHandler. Here is my implementation of it.
public void endElement(String uri, String localName, String qName) throws SAXException {
//I added the next three lines for debugging
System.out.println("Found End Element " + count + " times");
System.out.println("Localname = " + localName);
System.out.println("QName = " + qName);
super.endElement(uri, localName, qName);
if (this.currentItem != null){
if (localName.equalsIgnoreCase(me.osama.XMLParsing.BaseFeedParser.ITEMNAME)){
currentItem.setItemName(builder.toString());
} else if (localName.equalsIgnoreCase(me.osama.XMLParsing.BaseFeedParser.ITEMSITE)){
currentItem.setItemSite(builder.toString());
} else if (localName.equalsIgnoreCase(me.osama.XMLParsing.BaseFeedParser.ITEMNO)){
currentItem.setItemNo(builder.toString());
} else if (localName.equalsIgnoreCase(me.osama.XMLParsing.BaseFeedParser.ITEM)){
System.out.println(currentItem);
items.add(currentItem);
}
builder.setLength(0);
}
count++;
}
Turns out that localName kept on coming empty hence the conditions never held true and the code never went into the decision block. On the other hand qName brought all names out properly and once i changed the variable to qName the List<Item> items collection type did fill up and worked correctly.
I am here to ask why did qName work and not localName? Whereas the tutorial from IBM's DeveloperWorks used an RSS feed and localName worked perfectly for him.
P.S. this is the feed the IBM Tutorial used: http://www.androidster.com/android_news.rss

As per the SAX namespace for Java API,
By default, an XML reader will report a Namespace URI and a localName
for every element that belongs in a namespace, in both the start and
end handler.
Perhaps, if you add a namespace to the XML and define your elements in that namespace, it would return a valid localName. The article also mentions that with namespace processing, some implementations will return empty qName.

Related

Java - attributevalue from parents child

I'm currently working on a small weather API (From YR.NO) in Java.
The API is in XML as shown below:
NOTE : There are several of those "boxes" in the same API, just different time on them.
Whole XML shown
<time datatype="forecast" from="2016-09-08T21:00:00Z" to="2016-09-08T21:00:00Z">
<location altitude="47" latitude="59.3293235" longitude="18.0685808">
<temperature id="TTT" unit="celsius" value="12.0"/>
<windDirection id="dd" deg="121.8" name="SE"/>
<windSpeed id="ff" mps="2.2" beaufort="2" name="Svak vind"/>
<windGust id="ff_gust" mps="3.7"/>
<humidity value="80.5" unit="percent"/>
<pressure id="pr" unit="hPa" value="1016.0"/>
<cloudiness id="NN" percent="51.6"/>
<fog id="FOG" percent="-0.0"/>
<lowClouds id="LOW" percent="51.2"/>
<mediumClouds id="MEDIUM" percent="0.0"/>
<highClouds id="HIGH" percent="0.8"/>
<dewpointTemperature id="TD" unit="celsius" value="8.8"/>
</location>
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException
{
for (int i = 0; i < attributes.getLength(); i++)
{
String attributeName = attributes.getLocalName(i);
String attributeValue = attributes.getValue(i);
System.out.println(attributes.getLocalName(i) + " : " + attributes.getValue(i));
//if(attributeValue.toLowerCase().indexOf(timeCheck.toLowerCase()) != -1)
// {
// System.out.println("Temperature: " + attributes.getValue(i));
// }
}
With this ^ i can easily display all the Names with their values but I can't really figure out how to control it.
What I have now is a String that saves the user-input like:
String timeCheck = "T"+timeUserInput;
(If i input 15 then the timeCheck becomes "T15")
and then I check if some value obtains this input for example "T21" with this inside the for-loop:
if(attributeValue.toLowerCase().indexOf(timeCheck.toLowerCase()) != -1)
and then if's true I want to print the value of temperature which in this case is "12.0" but I can't seem to find an easy way of doing it. I can print ALL the temperature values but i ONLY want the temperature value of the right time.
Tried my best explaining my issue, recently started with Java, Thanks in advance! If you need an explanation of anything just tell me and i'll try.
To your purposes, I'd recommend you to use XPATH Api, a specific language to query an XML. The program would be like this:
public void getTemperature(org.w3c.dom.Document doc)
throws javax.xml.transform.TransformerException, javax.xml.xpath.XPathExpressionException
{
javax.xml.xpath.XPathFactory xpathFactory=javax.xml.xpath.XPathFactory.newInstance();
javax.xml.xpath.XPath xpath=xpathFactory.newXPath();
String temperature=(String)xpath.evaluate("product/time[contains(#from,'"+timeCheck+"')]/location/temperature/#value", doc, javax.xml.xpath.XPathConstants.STRING);
}

How to read namespace as it is in a xml using XMLStreamReader?

I have an xml file from which i read using an XMLStreamReader object.
So i'll keep it simple :
Let's take this xml example :
<mySample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attribute1="value1"/>
So what i need is to get the value (as a String) "xmlns:xsi" and get the value (as a String also) "http://www.w3.org/2001/XMLSchema-instance"
I did try to have a test like this :
if (reader.getEventType() != XMLStreamConstants.NAMESPACE){
attributeName = reader.getAttributeLocalName(i);
attributeValue = reader.getAttributeValue(i);
}
else{
attributeName = reader.getNamespacePrefix(i) + reader.getNamespaceURI(i);
attributeValue = reader.getAttributeValue(i);
}
But it did not work.
Obviously i missed something being a newbie to this API, so any help would be very welcome.
The JSR-173 specification (Stax API for Java) states the following regarding the NAMESPACE event :
Namespace
Namespace declarations can also exist outside of a StartElement and may be reported as a
standalone information item. In general Namespaces are reported as part of a StartElement
event. When namespaces are the result of an XQuery or XPath expression they may be
reported as standalone events.
So if you are looking at namespace events, you should most probably be checking StartElement events, and inspect them. Once again, from the spec :
Namespaces can be accessed using the following methods:
int getNamespaceCount();
String getNamespacePrefix(int index);
String getNamespaceURI(int index);
Only the namespaces declared on the current StartElement are available. The list does
not contain previously declared namespaces and does not remove redeclared namespaces.
At any point during the parsing, you can get the current complete namespace context :
The namespace context of the current state is available by calling
XMLStreamReader.getNamespaceContext() or
StartElement.getNamespaceContext(). These methods return an instance of the
javax.xml.namespace.NamespaceContext interface.
That's theory : most namespace declarations come from START_ELEMENT, some may come independently.
In practice, I have never came accross a NAMESPACE event reported by the API when reading from a file. It's almost always reported as part of a START_ELEMENT (and repeated in the corresponding END_ELEMENT), so you must check START_ELEMENT if you are interested in namespace declaration. For example, starting with your document :
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><mySample xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" attribute1=\"value1\"/>";
XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader(new StringReader(xml));
while (reader.hasNext()) {
int event = reader.next();
if (XMLStreamConstants.START_ELEMENT == event) {
if (reader.getNamespaceCount() > 0) {
// This happens
System.out.println("ELEMENT START: " + reader.getLocalName() + " , namespace count is: " + reader.getNamespaceCount());
for (int nsIndex = 0; nsIndex < reader.getNamespaceCount(); nsIndex++) {
String nsPrefix = reader.getNamespacePrefix(nsIndex);
String nsId = reader.getNamespaceURI(nsIndex);
System.out.println("\tNamepsace prefix: " + nsPrefix + " associated with URI " + nsId);
}
}
} else if(XMLStreamConstants.NAMESPACE == event) {
// This almost never happens
System.out.println("NAMESPACE EVENT");
}
}
Will produce :
ELEMENT START: mySample , namespace count is: 1
Namepsace prefix: xsi associated with URI http://www.w3.org/2001/XMLSchema-instance
Bottom line : you should check for NAMESPACE and START_ELEMENT events, even if most of times, you will only have START_ELEMENT reporting namespace declartions, it is not one or the other, it's both.

SAX Parsing in Android Searching Attribute

Im trying to identify an attribute using SAX. My XML is as follows
<DAY VALUE="1">
<BREAKFAST>0700</BREAKFAST>
<LUNCH>1200</LUNCH>
<DINNER>1900</DINNER>
</DAY>
<DAY VALUE="2">
<BREAKFAST>0730</BREAKFAST>
<LUNCH>1230</LUNCH>
<DINNER>1930</DINNER>
</DAY>
and my startElement code is as follows:
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
elementOn = true;
if (localName.equals("DAY"))
{
data = new XMLGettersSetters();
}
}
The above code will find the first element "DAY" and give me the contents but not the remaining DAY elements.
Is there a way I can search for the attribute? I am aiming to get the current day in the month and then search for the day within the xml. For example if today is the 2nd then I want to search in the XML file for DAY VALUE="2" and get the sub elements
==EDIT
If i modify my XML to
<DAY_1>
<BREAKFAST>0700</BREAKFAST>
<LUNCH>1200</LUNCH>
<DINNER>1900</DINNER>
</DAY_1>
<DAY_2>
<BREAKFAST>0730</BREAKFAST>
<LUNCH>1230</LUNCH>
<DINNER>1930</DINNER>
</DAY_2>
and code to:
if (localName.equals("DAY_2"))
{
data = new XMLGettersSetters();
}
I get a NullPointerException however the name if the class is not highlighted in logcat. It was referring to another class but i commented out those lines
you can get attribute value like this:
if (localName.equals("DAY")){
String day = "";
if (attributes.getValue("VALUE") != null) {
day = attributes.getValue("VALUE");
}
//data = new XMLGettersSetters();
}

How to Parse XML Response of Http Post in Java

I have an XML response from HTTP POST of this form
<PaymentResponse><TransDate>301111</TransDate><TransTime>011505</TransTime><SourceID>0</SourceID><Balance>0</Balance><ResponseCode>06</ResponseCode><ResponseMessage>Error XXXX</ResponseMessage><ApprovalCode>DECL</ApprovalCode><ApprovalAmount>0</ApprovalAmount></PaymentResponse>
But I am unable to parse it using Sax parser. Kindly help me out.
regards
I am using this code
public void endElement(String uri, String localName, String qName) throws SAXException {
if(localName.equalsIgnoreCase("TransDate"))
{
int tD = Integer.parseInt(currentValue);
tempResponse.setTDate(tD);
}
But every time localName comes with empty string.
As to your specific question: have a look at 'qName' argument instead: local name is only populated when parser uses namespace-aware mode. qName should contain "qualified" name, ie. concatenation of prefix (if any) and local name; so something like "ns:element" (if there is a prefix), or "element" (if no prefix).

Parsing http returned xml with java

So I've tried searching and searching on how to do this but I keep seeing a lot of complicated answers for what I need. I basically am using the Flurry Analytics API to return some xml code from an HTTP request and this is what it returns.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<eventMetrics type="Event" startDate="2011-2-28" eventName="Tip Calculated" endDate="2011-3-1" version="1.0" generatedDate="3/1/11 11:32 AM">
<day uniqueUsers="1" totalSessions="24" totalCount="3" date="2011-02-28"/>
<day uniqueUsers="0" totalSessions="0" totalCount="0" date="2011-03-01"/>
<parameters/>
</eventMetrics>
All I want to get is that totalCount number which is 3 with Java to an int or string. I've looked at the different DOM and SAX methods and they seem to grab information outside of the tags. Is there someway I can just grab totalCount within the tag?
Thanks,
Update
I found this url -http://www.androidpeople.com/android-xml-parsing-tutorial-%E2%80%93-using-domparser/
That helped me considering it was in android. But I thank everyone who responded for helping me out. I checked out every answer and it helped out a little bit for getting to understand what's going on. However, now I can't seem to grab the xml from my url because it requires an HTTP post first to then get the xml. When it goes to grab xml from my url it just says file not found.
Update 2
I got it all sorted out reading it in now and getting the xml from Flurry Analytics (for reference if anyone stumbles upon this question)
HTTP request for XML file
totalCount is what we call an attribute. If you're using the org.w3c.dom API, you call getAttribute("totalCount") on the appropriate element.
If you are using an SAX handler, override the startElement callback method to access attributes:
public void startElement (String uri, String name, String qName, Attributes atts)
{
if("day".equals (qName)) {
String total = attrs.getValue("totalCount");
}
}
A JDOM example. Note the use of SAXBuilder to load the document.
URL httpSource = new URL("some url string");
Document document = SAXBuilder.build(httpSource);
List<?> elements = document.getDescendants(new KeyFilter());
for (Element e : elements) {
//do something more useful with it than this
String total = (Element) e.getAttributeValue("totalCount");
}
class KeyFilter implements Filter {
public boolean matches (Object obj) {
return (Element) obj.getName().equals("key");
}
}
I think that the simplest way is to use XPath, below is an example based on vtd-xml.
import com.ximpleware.*;
public class test {
public static void main(String[] args) throws Exception {
String xpathExpr = "/eventMetrics/day/#totalCount";
VTDGen vg = new VTDGen();
int i = -1;
if (vg.parseHttpUrl("http://localhost/test.xml", true)) {
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot();
ap.selectXPath(xpathExpr);
ap.bind(vn);
System.out.println("total count "+(int)ap.evalXPathtoDouble());
}
}
}

Categories