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();
}
Related
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);
}
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.
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).
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());
}
}
}
I have a XmlDocument in java, created with the Weblogic XmlDocument parser.
I want to replace the content of a tag in this XMLDocument with my own data, or insert the tag if it isn't there.
<customdata>
<tag1 />
<tag2>mfkdslmlfkm</tag2>
<location />
<tag3 />
</customdata>
For example I want to insert a URL in the location tag:
<location>http://something</location>
but otherwise leave the XML as is.
Currently I use a XMLCursor:
XmlObject xmlobj = XmlObject.Factory.parse(a.getCustomData(), options);
XmlCursor xmlcur = xmlobj.newCursor();
while (xmlcur.hasNextToken()) {
boolean found = false;
if (xmlcur.isStart() && "schema-location".equals(xmlcur.getName().toString())) {
xmlcur.setTextValue("http://replaced");
System.out.println("replaced");
found = true;
} else if (xmlcur.isStart() && "customdata".equals(xmlcur.getName().toString())) {
xmlcur.push();
} else if (xmlcur.isEnddoc()) {
if (!found) {
xmlcur.pop();
xmlcur.toEndToken();
xmlcur.insertElementWithText("schema-location", "http://inserted");
System.out.println("inserted");
}
}
xmlcur.toNextToken();
}
I tried to find a "quick" xquery way to do this since the XmlDocument has an execQuery method, but didn't find it very easy.
Do anyone have a better way than this? It seems a bit elaborate.
How about an XPath based approach? I like this approach as the logic is super-easy to understand. The code is pretty much self-documenting.
If your xml document is available to you as an org.w3c.dom.Document object (as most parsers return), then you could do something like the following:
// get the list of customdata nodes
NodeList customDataNodeSet = findNodes(document, "//customdata" );
for (int i=0 ; i < customDataNodeSet.getLength() ; i++) {
Node customDataNode = customDataNodeSet.item( i );
// get the location nodes (if any) within this one customdata node
NodeList locationNodeSet = findNodes(customDataNode, "location" );
if (locationNodeSet.getLength() > 0) {
// replace
locationNodeSet.item( 0 ).setTextContent( "http://stackoverflow.com/" );
}
else {
// insert
Element newLocationNode = document.createElement( "location" );
newLocationNode.setTextContent("http://stackoverflow.com/" );
customDataNode.appendChild( newLocationNode );
}
}
And here's the helper method findNodes that does the XPath search.
private NodeList findNodes( Object obj, String xPathString )
throws XPathExpressionException {
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression expression = xPath.compile( xPathString );
return (NodeList) expression.evaluate( obj, XPathConstants.NODESET );
}
How about an object oriented approach? You could deserialise the XML to an object, set the location value on the object, then serialise back to XML.
XStream makes this really easy.
For example, you would define the main object, which in your case is CustomData (I'm using public fields to keep the example simple):
public class CustomData {
public String tag1;
public String tag2;
public String location;
public String tag3;
}
Then you initialize XStream:
XStream xstream = new XStream();
// if you need to output the main tag in lowercase, use the following line
xstream.alias("customdata", CustomData.class);
Now you can construct an object from XML, set the location field on the object and regenerate the XML:
CustomData d = (CustomData)xstream.fromXML(xml);
d.location = "http://stackoverflow.com";
xml = xstream.toXML(d);
How does that sound?
If you don't know the schema the XStream solution probably isn't the way to go. At least XStream is on your radar now, might come in handy in the future!
You should be able to do this with query
try
fn:replace(string,pattern,replace)
I am new to xquery myself and I have found it to be a painful query language to work with, but it does work quiet well once you get over the initial learning curve.
I do still wish there was an easier way which was as efficient?