XmlPullParserException during parsing XML with XMLPullParser - java

Need your help to resolve this :
Trying to parse this xml -
<LungProtocol><configuration name="FLUS Sitting">
<segment order="1" name="left upper anterior">
<segment order="2" name="left lower anterior">
</configuration>
<configuration name="FLUS Supine">
<segment order="1" name="left upper anterior">
<segment order="2" name="left lower anterior">
</configuration></LungProtocol>
With following function -
public List<LungSegment> parse(InputStream is, String configuration) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = factory.newPullParser();
segment = new LungSegment();
parser.setInput(is, null);
parser.require(XmlPullParser.START_TAG, null, "configuration");
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String tagname = parser.getName();
switch (eventType) {
case XmlPullParser.START_TAG:
if(("configuration").equalsIgnoreCase(tagname) && parser.getAttributeValue(null, "name").equalsIgnoreCase(configuration)){
eventType = parser.next();
//eventType = parser.next();
tagname = parser.getName();
Log.v("XMLTAG", "configuration = "+configuration);
if (("segment").equalsIgnoreCase(tagname)) {
// create a new instance of segment
segment = new LungSegment();
segment.setSegmentName(parser.getAttributeValue(null, "name"));
segment.setSegmentOrder(Integer.parseInt(parser.getAttributeValue(null, "order")));
}
}
break;
case XmlPullParser.END_TAG:
if (tagname.equalsIgnoreCase("segment")) {
// add segment object to list
segments.add(segment);
} else if (("configuration").equalsIgnoreCase(tagname) && parser.getAttributeValue(null, "name").equalsIgnoreCase(configuration)) {
return segments;
}
break;
}
eventType = parser.next();
}
} catch (XmlPullParserException e) {e.printStackTrace();}
catch (IOException e) {e.printStackTrace();}
return segments;
}
where configuration is the name attribute of configuration tag. But getting an exception -
org.xmlpull.v1.XmlPullParserException: expected: START_TAG {null}configuration (position:START_DOCUMENT null#1:1 in java.io.InputStreamReader#42323800)
Please help me where I am going wrong.

Make these two changes in your code:
Make xml valid. The segment tags are not ended. They should be:<segment order="1" name="left upper anterior"/>
Remove the line parser.require(XmlPullParser.START_TAG, null, "configuration");
Everything else looks fine. I was able to run your code as well.

Related

some suggestions for using STAX Parsing in java

I have a XML document which has at the top of it database configurations like username, password and URL and after that it has a tag called data and inside that it has data about employees and data about department that I want to pull it from the XML and insert it into a database.
I have managed to read the JDBC config and set it in a bean that return a connection and successfully worked, but now my problem is with the data tag how can I ignore the JDBC config from the XML file and read the data tag and insert it to a database, I know I can do it like
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
currentName = startElement.getName();
if(!currentName.equals("connection-setteings")) ...
But its not a good idea as I believe so can someone advice a better approach for that?
Here is the XML file:
<?xml version="1.0" encoding="UTF-8"?>
<import-request xmlns="http://www.phi01tech.com/tools/data-import" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.phi01tech.com/tools/data-import data-import.xsd ">
<connection-settings>
<username>root</username>
<password>root</password>
<url>jdbc:mysql://localhost:3306/sample</url>
<driverClassName>com.mysql.jdbc.Driver</driverClassName>
</connection-settings>
<data>
<departments dept_no="d009" dept_name="Customer Service"/>
<departments dept_no="d005" dept_name="Development"/>
<departments dept_no="d002" dept_name="Finance"/>
<departments dept_no="d003" dept_name="Human Resources"/>
<departments dept_no="d001" dept_name="Marketing"/>
<departments dept_no="d004" dept_name="Production"/>
<departments dept_no="d006" dept_name="Quality Management"/>
<departments dept_no="d008" dept_name="Research"/>
<departments dept_no="d007" dept_name="Sales"/>
<employees emp_no="10001" birth_date="1953-09-02" first_name="Georgi" last_name="Facello" gender="M"
hire_date="1986-06-26"/>
<employees emp_no="10002" birth_date="1964-06-02" first_name="Bezalel" last_name="Simmel" gender="F"
hire_date="1985-11-21"/>
<employees emp_no="10003" birth_date="1959-12-03" first_name="Parto" last_name="Bamford" gender="M"
hire_date="1986-08-28"/>
<employees emp_no="10004" birth_date="1954-05-01" first_name="Chirstian" last_name="Koblick" gender="M"
hire_date="1986-12-01"/>
<employees emp_no="10005" birth_date="1955-01-21" first_name="Kyoichi" last_name="Maliniak" gender="M"
hire_date="1989-09-12"/>
<employees emp_no="10006" birth_date="1953-04-20" first_name="Anneke" last_name="Preusig" gender="F"
hire_date="1989-06-02"/>
<employees emp_no="10007" birth_date="1957-05-23" first_name="Tzvetan" last_name="Zielinski" gender="F"
hire_date="1989-02-10"/>
<employees emp_no="10008" birth_date="1958-02-19" first_name="Saniya" last_name="Kalloufi" gender="M"
hire_date="1994-09-15"/>
</data>
</import-request>
And here is my java class:
public class STAXParser {
static ConnectionManager connectionManager = new ConnectionManager();
String currentName;
public void parseDocuments() throws IOException, XMLStreamException {
XMLInputFactory inputFactory = XMLInputFactory.newFactory();
try (InputStream stream = Files.newInputStream(Paths.get("emp.xml"))) {
XMLEventReader reader = inputFactory.createXMLEventReader(stream);
while (reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
currentName = startElement.getName().getLocalPart();
System.out.println(startElement.getName());
Iterator attributes = startElement.getAttributes();
while(attributes.hasNext()) {
//System.out.println(attributes.next());
}
}
if (event.isCharacters()) {
if (!event.asCharacters().isWhiteSpace()) {
String data = event.asCharacters().getData();
checkName(currentName, data.trim());
}
}
}
}
}
private void checkName(String name, String event) {
if (name.equals("url"))
connectionManager.setUrl(event);
else if (name.equals("username"))
connectionManager.setUsername(event);
else if (name.equals("password"))
connectionManager.setPassword(event);
else if (name.equals("driverClassName"))
connectionManager.setDriver(event);
}
public static void main(String[] args) {
STAXParser s = new STAXParser();
try {
s.parseDocuments();
} catch (IOException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}
try {
connectionManager.getConnection().toString();
JDBCEmployeeDao d = new JDBCEmployeeDao(connectionManager);
// d.create();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
I find that XMLStreamReader is much easier to use, since elements can be processed in context of the parent, unlike XMLEventReader that returns all events in a flat sequence.
Example of parsing your XML using XMLStreamReader. For simplicity of the example, the code ignores namespaces.
public static void main(String[] args) throws Exception {
XMLInputFactory inputFactory = XMLInputFactory.newFactory();
Connection connection = null;
try (InputStream stream = Files.newInputStream(Paths.get("src/main/resources/test.xml"))) {
XMLStreamReader reader = inputFactory.createXMLStreamReader(stream);
reader.nextTag(); // Position on root tag
if (! reader.getLocalName().equals("import-request"))
throw new XMLStreamException("Invalid root element: " + reader.getLocalName());
while (reader.nextTag() == XMLStreamConstants.START_ELEMENT) {
switch (reader.getLocalName()) {
case "connection-settings":
connection = parseConnectionSettings(reader);
break;
case "data":
if (connection == null)
throw new XMLStreamException("Missing <connection-settings> before <data>");
parseData(reader, connection);
break;
default:
// ignore unknown content
}
}
} finally {
if (connection != null)
connection.close();
}
}
private static Connection parseConnectionSettings(XMLStreamReader reader) throws Exception {
String username = null, password = null, url = null, driverClassName = null;
while (reader.nextTag() == XMLStreamConstants.START_ELEMENT) {
switch (reader.getLocalName()) {
case "username":
username = reader.getElementText();
break;
case "password":
password = reader.getElementText();
break;
case "url":
url = reader.getElementText();
break;
case "driverClassName":
driverClassName = reader.getElementText();
break;
default:
throw new XMLStreamException("Invalid element in <connection-settings>: " + reader.getLocalName());
}
}
Class.forName(driverClassName);
return DriverManager.getConnection(url, username, password);
}
private static void parseData(XMLStreamReader reader, Connection connection) throws Exception {
while (reader.nextTag() == XMLStreamConstants.START_ELEMENT) {
switch (reader.getLocalName()) {
case "departments":
processDepartments(reader, connection);
break;
case "employees":
processEmployees(reader, connection);
break;
default:
throw new XMLStreamException("Invalid element in <data>: " + reader.getLocalName());
}
}
}
private static void processDepartments(XMLStreamReader reader, Connection connection) throws Exception {
String dept_no = reader.getAttributeValue(null, "dept_no");
String dept_name = reader.getAttributeValue(null, "dept_name");
if (! reader.getElementText().isEmpty())
throw new XMLStreamException("<departments> must be empty element");
// process here
}
private static void processEmployees(XMLStreamReader reader, Connection connection) throws Exception {
// code here
}

Parsing XML not parsing whole file

I have this XML
<CurrencyExchangeMap>
<CurrencyExchangePoint>
<Address>addr 3</Address>
<Latitude>41.6940265</Latitude>
<Longitude>44.7985044</Longitude>
</CurrencyExchangePoint>
<CurrencyExchangePoint>
<Address>addr 4</Address>
<Latitude>41.7024424</Latitude>
<Longitude>44.8058617</Longitude>
</CurrencyExchangePoint>
<CurrencyExchangePoint>
<Address>addr 5</Address>
<Latitude>41.6954418</Latitude>
<Longitude>44.7046725</Longitude>
</CurrencyExchangePoint>
</CurrencyExchangeMap>
It has 1000+ CurrencyExchangePoint But when I'm parsin them it returns ONLY 167 item. What's wrong? I've checked xml file in stylus studio and by myself and didn't find any error.
List<MapLT> mapLTs = null;
try {
XMLPullParserHandler parserHandler = new XMLPullParserHandler();
mapLTs = parserHandler.parse(getAssets().open("ltlg.xml"));
for (MapLT item : mapLTs) {
LatLng lt = new LatLng(item.getLatitude(), item.getLongitude());
String title = item.getAddress();
googleMap.addMarker(new MarkerOptions().position(lt).title(title));
}
} catch (Exception ex) {
ex.printStackTrace();
}
and my xmlpullparse class:
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
public class XMLPullParserHandler {
List<MapLT> mapLTList;
private MapLT mapLT;
private String text;
public XMLPullParserHandler() {
mapLTList = new ArrayList<MapLT>();
}
public List<MapLT> getMapLT(){
return mapLTList;
}
public List<MapLT> parse(InputStream is){
XmlPullParserFactory factory = null;
XmlPullParser parser = null;
try{
factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
parser = factory.newPullParser();
parser.setInput(is, null);
int eventType = parser.getEventType();
while(eventType != XmlPullParser.END_DOCUMENT){
String tagname = parser.getName();
switch (eventType){
case XmlPullParser.START_TAG:
if(tagname.equalsIgnoreCase("CurrencyExchangePoint")){
mapLT = new MapLT();
}
break;
case XmlPullParser.TEXT:
text = parser.getText();
break;
case XmlPullParser.END_TAG:
if(tagname.equalsIgnoreCase("CurrencyExchangePoint")){
mapLTList.add(mapLT);
} else if(tagname.equalsIgnoreCase("Address")){
mapLT.setAddress(text);
} else if(tagname.equalsIgnoreCase("Latitude")){
mapLT.setLatitude(Float.parseFloat(text));
} else if(tagname.equalsIgnoreCase("Longitude")){
mapLT.setLongitude(Float.parseFloat(text));
}
break;
default:
break;
}
eventType = parser.next();
}
}catch (Exception ex){
ex.printStackTrace();
}
return mapLTList;
}
}
I can't spot a problem in your code, so my strategy would be to add logs.
Start by printing all the event tags and tag names you get.
Problem was that value of one tag from 6500 was empty..
And it took my 4 hour

XMLPullParser android colon tags

I have found several questions of the name question, but can't get any of them to work. What I want is to get the url of the media:thumbnail tag:
<media:thumbnail width="144" height="81" url="http://c.files.bbci.co.uk/6013/production/_88159542_3e6f2bc3-16a3-407d-9e07-62bae1fa755e.jpg"/>
Above the example of such tag
private void handleText(String text) {
String xmlText = text;
if (currentEntry != null && currentTag != null) {
if (currentTag.equals(TITLE)) {
currentEntry.setTitle(xmlText);
} else if (currentTag.equals(DESC)) {
currentEntry.setDescription(xmlText);
} else if (currentTag.equals(LINK)) {
currentEntry.setLink(xmlText);
} else if (currentTag.equals(IMAGE)) {
currentEntry.setImage("test");
}
}
}
I tried several things as:
xpp.getAttributeValue(null, "url"); and set the image as that. However I noticed that I am not even getting in that else if clause. I tried several values on the IMAGE variable like:
media:thumbnail
media
thumbnail
I have also set namespace aware:
factory.setNamespaceAware(true);
What am I doing wrong?
parser:
XmlPullParser xpp;
int eventType;
protected List<Entry> doInBackground(String... string) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
xpp = factory.newPullParser();
xpp.setInput(getInputStream(new URL("http://feeds.bbci.co.uk/news/technology/rss.xml?edition=uk")), "UTF_8");
eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
handleStartTag(xpp.getName());
} else if (eventType == XmlPullParser.END_TAG) {
currentTag = null;
} else if (eventType == XmlPullParser.TEXT) {
handleText(xpp.getText());
}
eventType = xpp.next();
}
} catch (Resources.NotFoundException e) {
Log.d(LOGTAG, e.getMessage());
} catch (XmlPullParserException e) {
Log.d(LOGTAG, e.getMessage());
} catch (IOException e) {
Log.d(LOGTAG, e.getMessage());
}
return entries;
}
I fixed it. I systemed out the start tags it was parsing and it showed up as: thumbnail. So I changed my IMAGE constant to have the value of "thumbnail". It never came in the thumbnail clause since the handleText method only handles found text in a tag. Since media:thumbnail has no text only attributes with values I needed to handle it in the handleStartTag method. There I could say if the current tag name equals "thumbnail" get the attribute value of url and setImage as that value.

Read child nodes with same name using StAX

While trying to read XML file using StAX I came across this problem.
In an XML file (essentially its an XLIFF file), I have child nodes with the same name.
I couldn't quite figure out how to read these duplicate nodes.
Below is the part of code that I am trying on, and an example of the XLIFF file as well
This is only the working part of the code.
Java Code:
// Initialize ArrayList to return
ArrayList<SourceCollection> xmlData = new ArrayList<>();
boolean isSource = false;
boolean isTrans = false;
boolean isContext = false;
// Setting Up Data Class
SourceCollection srcData = null;
// Start StAX XLIFF reader
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inStream);
int event = xmlStreamReader.getEventType();
while (true) {
switch (event) {
case XMLStreamConstants.START_ELEMENT:
switch (xmlStreamReader.getLocalName()) {
case "group":
// Create SourceCollection Object
srcData = new SourceCollection();
srcData.setID(xmlStreamReader.getAttributeValue(0));
break;
case "source":
isSource = true;
break;
case "target":
isTarget = true;
break;
case "context":
isContext = true;
break;
default:
isSource = false;
isTarget = false;
isContext = false;
break;
}
break;
case XMLStreamConstants.CHARACTERS:
if (srcData != null) {
String srcTrns = xmlStreamReader.getText();
if (!Utility.isStringNullOrEmptyOrWhiteSpace(srcTrns)) {
if (isSource) {
srcData.setSource(srcTrns);
isSource = false;
} else if (isTarget) {
srcData.setTarget(srcTrns);
isTarget = false;
}
}
}
break;
case XMLStreamConstants.END_ELEMENT:
if (xmlStreamReader.getLocalName().equals("group")) {
xmlData.add(srcData);
}
break;
}
if (!xmlStreamReader.hasNext()) {
break;
}
event = xmlStreamReader.next();
}
} catch (XMLStreamException ex) {
LOG.log(Level.WARNING, ex.getMessage(), MessageFormat.format("{0} {1}", ex.getCause(), ex.getLocation()));
}
XLIFF file sample:
<XLIFF>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<file datatype="xml">
<body>
<group id="25032014">
<context-group>
<context context-type="sub1">xxxx</context>
<context context-type="sub2">yyyy</context>
<context context-type="sub3"/>
</context-group>
<target-unit>
<source>ABC</source>
<target>ABC</target>
</target-unit>
</group>
</body>
</file>
</xliff>
</XLIFF>
Of course, this is a modified XLIFF file, but structure is exactly the same as original.
Any sample or suggestions would be helpful.
But you already process these duplicates. I modified your code a little like
switch (event) {
case XMLStreamConstants.START_ELEMENT:
System.out.println(xmlStreamReader.getLocalName());
switch (xmlStreamReader.getLocalName()) {
and the System.out delivers:
XLIFF
xliff
file
body
group
context-group
context
context
context
target-unit
source
target
You see the multiple context outputs. Now you have to adapt your data structure to hold lists of context elements and not only one.

Android: Xml Pull Parser not working

I'm trying to extract data from an Xml file, I followed this tutorial:
XmlPullParser tutorial
And now have the following code:
public void parse(InputStream is) {
// create new Study object to hold data
try {
// get a new XmlPullParser object from Factory
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
// set input source
parser.setInput(is, null);
// get event type
int eventType = parser.getEventType();
// process tag while not reaching the end of document
while(eventType != XmlPullParser.END_DOCUMENT) {
switch(eventType) {
// at start of document: START_DOCUMENT
case XmlPullParser.START_DOCUMENT:
break;
// at start of a tag: START_TAG
case XmlPullParser.START_TAG:
// get tag name
String tagName = parser.getName();
Log.i("AT START TAG","AT START TAG..."+tagName);
// if <study>, get attribute: 'id'
if(tagName.equalsIgnoreCase("Date")) {
Log.i("****PARSER INFO","TAG NAME="+tagName+"...."+parser.nextText());
eventDates.add(parser.nextText());
//study.mId = Integer.parseInt(parser.getAttributeValue(null, Study.ID));
}
// if <content>
else if(tagName.equalsIgnoreCase("Name")) {
Log.i("****PARSER INFO","TAG NAME="+tagName+"...."+parser.nextText());
performanceNames.add(parser.nextText());
//study.mContent = parser.nextText();
}
// if <topic>
else if(tagName.equalsIgnoreCase("RequestURL")) {
Log.i("****PARSER INFO","TAG NAME="+tagName+"...."+parser.nextText());
eventsURLS.add(parser.nextText());
//study.mTopic = parser.nextText();
}
break;
}
// jump to next event
eventType = parser.next();
}
// exception stuffs
} catch (XmlPullParserException e) {
//study = null;
} catch (IOException e) {
//study = null;
}
// return Study object
}
For some reason, the code within the IF statements is not running even though I have made sure the tag names do equal the strings above.
What am I doing wrong?

Categories

Resources