I'm passing in an XML file and a handler to the SAXParser but I'm getting this error:
The attributes for the parse method are defined as (File, DefaultHandler) which match exactly, so I'm not sure where I'm going wrong. Here is the full method:
public String readXML (File readFile) throws Exception {
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxFactory.newSAXParser();
final String outputString = "";
DefaultHandler handler = new DefaultHandler() {
boolean bArtist = false;
boolean bAlbumName = false;
boolean bYear = false;
boolean bGenre = false;
public void startElement(String uri, String localName, String qName, Attributes attr)
throws SAXException {
if (qName.equalsIgnoreCase("ARTIST")) { bArtist = true; }
if (qName.equalsIgnoreCase("ALBUMNAME")) { bAlbumName = true; }
if (qName.equalsIgnoreCase("YEAR")) { bYear = true; }
if (qName.equalsIgnoreCase("GENRE")) { bGenre = true; }
}
public void characters(char ch[], int start, int length) {
if (bArtist) {
outputString.concat("Artist: " + new String(ch,start,length) + "\n");
}
if(bAlbumName) {
outputString.concat("Album: " + new String(ch,start,length) + "\n");
}
if(bYear) {
outputString.concat("Year: " + new String(ch,start,length) + "\n");
}
if(bGenre) {
outputString.concat("Genre: " + new String(ch,start,length) + "\n");
}
outputString.concat("\n");
}
};
saxParser.parse(readFile,handler);
return outputString;
}
It should be org.xml.sax.helpers.DefaultHandler
not jdk.internal...
so
import org.xml.sax.helpers.DefaultHandler;
You should probably also define the class that extends the DefaultHandler not just inline it.
Related
Previously, I was able to display the data of one tag, but this time not several values are displayed, but only one.
This my parser code:
public class Runner {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
MyHandler handler = new MyHandler();
xmlReader.setContentHandler(handler);
xmlReader.parse("src/countries.xml");
Countries branches = handler.getBranches();
try (FileWriter files = new FileWriter("src/diploma/SAX.txt")) {
files.write("Item " + "\n" + String.valueOf(branches.itemList) + "\n");
}
}
private static class MyHandler extends DefaultHandler{
static final String HISTORY_TAG = "history";
static final String ITEM_TAG = "item";
static final String NAME_ATTRIBUTE = "name";
public Countries branches;
public Item currentItem;
private String currencyElement;
Countries getBranches(){
return branches;
}
public void startDocument() throws SAXException {
}
#Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currencyElement = qName;
switch (currencyElement) {
case HISTORY_TAG: {
branches.itemList = new ArrayList<>();
currentItem = new Item();
currentItem.setHistoryName(String.valueOf(attributes.getValue(NAME_ATTRIBUTE)));
} break;
default: {}
}
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
String text = new String(ch, start, length);
if (text.contains("<") || currencyElement == null){
return;
}
switch (currencyElement) {
case ITEM_TAG: {
currentItem.setItem(text);
} break;
default: { }
}
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException{
switch (qName) {
case HISTORY_TAG: {
branches.itemList.add(currentItem);
currentItem = null;
} break;
default: {
}
}
currencyElement = null;
}
public void endDocument() throws SAXException {
System.out.println("SAX parsing is completed...");
}
}
}
Class Item:
public class Item {
private String historyName;
private String item;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public String getHistoryName() {
return historyName;
}
public void setHistoryName(String historyName) {
this.historyName = historyName;
}
#Override
public String toString() {
return
"historyName = " + historyName + ", " + "\n" + "item = " + item + ", ";
}
}
And class Countries
public class Countries {
public List<Item> itemList;
}
I have problems with this part
<history name="История">
<item>
История белорусских земель очень богата и самобытна.
</item>
<item>
Эту страну постоянно раздирали внутренние конфликты и противоречия, много раз она была втянута в войны.
</item>
<item>
В 1945 году Беларусь вступила в состав членов-основателей Организации Объединенных Наций.
</item>
</history>
I only display the last "item" tag, and other duplicate tags are displayed only in the singular. I can't figure out where the error is, but I noticed that in "endElement" all values are displayed, but as one element. Maybe someone knows what's the matter?
You are creating a new ArrayList every time you encounter the item tag.
That is why you only see one item displayed after parsing.
Now I use the sax parser to analysis the xml file(the following sample code comes from tutorialspoint). I want to output all the things to a txt file using the BufferedWriter when we call the characters function, while I don't get a way to make this. If I write this BufferedWriter in the characters function, it will only output the last string, since it will only record the last call. If I write this BufferedWriter in the main function, since they are two classes, the UserHandler couldn't recognize the BufferedWriter created in the main function(the dblpSax class). I also tried sth to make a class instance, while I still got involved troubles. Could you give me a way to make this? Thanks.
The Bufferwriter I want to use is as follows:
File writename = new File("output.txt");
writename.createNewFile();
BufferedWriter out = new BufferedWriter(new FileWriter(writename));
public class dblpSax{
public static void main(String[] args){
try {
File inputFile = new File("student.txt");
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
UserHandler userhandler = new UserHandler();
saxParser.parse(inputFile, userhandler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class UserHandler extends DefaultHandler {
boolean bFirstName = false;
boolean bLastName = false;
boolean bNickName = false;
boolean bMarks = false;
public void startElement(String uri,
String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equalsIgnoreCase("student")) {
String rollNo = attributes.getValue("rollno");
System.out.println("Roll No : " + rollNo);
} else if (qName.equalsIgnoreCase("firstname")) {
bFirstName = true;
} else if (qName.equalsIgnoreCase("lastname")) {
bLastName = true;
} else if (qName.equalsIgnoreCase("nickname")) {
bNickName = true;
}
else if (qName.equalsIgnoreCase("marks")) {
bMarks = true;
}
}
public void endElement(String uri,
String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("student")) {
System.out.println("End Element :" + qName);
}
}
public void characters(char ch[],
int start, int length) throws SAXException {
if (bFirstName) {
System.out.println("First Name: "
+ new String(ch, start, length));
bFirstName = false;
} else if (bLastName) {
System.out.println("Last Name: "
+ new String(ch, start, length));
bLastName = false;
} else if (bNickName) {
System.out.println("Nick Name: "
+ new String(ch, start, length));
bNickName = false;
} else if (bMarks) {
System.out.println("Marks: "
+ new String(ch, start, length));
bMarks = false;
}
}
}
You need a BufferedWriter at the same level as the parsing, best customizable outside the DefaultHandler.
try (BufferedWriter out = new BufferedWriter(....)) {
UserHandler userhandler = new UserHandler(out);
saxParser.parse(inputFile, userhandler);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class UserHandler extends DefaultHandler {
private final BufferedWriter out; // Or PrintWriter
UserHandler(BufferedWriter out) {
this.out = out;
}
And then one can all out.write everywhere.
I have XML file and I want to get position of a node.
<Root>
<Node1></Node1>
</Root>
I want to get 1) start and end positions; 2) start and end lines
How to do that? Thanks
Create a Reader that keeps track of position information you want:
static public class MyReader extends Reader {
final private Reader internalReader;
private int pos;
private int line;
public MyReader(Reader internalReader) {
this.internalReader = internalReader;
}
public int getPos() {
return pos;
}
public int getLine() {
return line;
}
#Override
public int read(char[] cbuf, int off, int len) throws IOException {
int chars_read = internalReader.read(cbuf, off, 1);
pos += chars_read;
if(cbuf[off] =='\n' && chars_read > 0) {
line++;
}
return chars_read;
}
#Override
public void close() throws IOException {
internalReader.close();
}
}
Use that with a ContentHandler that stores the position information in some data structure associated with the elements.
String xmlString = "<Root>\n"
+ " <Node1></Node1>\n"
+ "</Root>";
StringReader strReader = new StringReader(xmlString);
MyReader reader = new MyReader(strReader);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
Map<String,List<Integer>> startMap = new HashMap<>();
Map<String,List<Integer>> endMap = new HashMap<>();
Map<String,List<Integer>> startLineMap = new HashMap<>();
Map<String,List<Integer>> endLineMap = new HashMap<>();
DefaultHandler handler = new DefaultHandler() {
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName); //To change body of generated methods, choose Tools | Templates.
List<Integer> l = endMap.get(qName);
if(null == l) {
l = new ArrayList<>();
}
l.add(reader.getPos());
endMap.put(qName, l);
List<Integer> ll = endLineMap.get(qName);
if(null == ll) {
ll= new ArrayList<>();
}
ll.add(reader.getLine());
endLineMap.put(qName, ll);
}
#Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes); //To change body of generated methods, choose Tools | Templates.
List<Integer> l = startMap.get(qName);
if(null == l) {
l = new ArrayList<>();
}
l.add(reader.getPos());
startMap.put(qName, l);
List<Integer> ll = startLineMap.get(qName);
if(null == ll) {
ll= new ArrayList<>();
}
ll.add(reader.getLine());
startLineMap.put(qName, ll);
}
};
xmlreader.setContentHandler(handler);
xmlreader.parse(new InputSource(reader));
System.out.println("startMap = " + startMap);
System.out.println("endMap = " + endMap);
System.out.println("startLineMap = " + startLineMap);
System.out.println("endLineMap = " + endLineMap);
I have used script below and the output is
X value : 123
Y value : 123
X value : 123
Y value : 130
how can I set first X as X0; first Y as Y0 and second X as X1 and second Y as Y1 ? I used SAX parser, it has processed my input file properly, and now i want to define X0, X1, Y0, Y1 in order to draw line
public static void main(String argv[]) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
boolean xele = false;
boolean yele = false;
public void startElement(String uri, String localName,String qName,
Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("X")) {
xele = true;
}
if (qName.equalsIgnoreCase("Y")) {
yele = true;
}
}
public void characters(char ch[], int start, int length) throws SAXException {
if (xele) {
System.out.println("X value : " + new String(ch, start, length));
xele = false;
}
if (yele) {
System.out.println("Y value : " + new String(ch, start, length));
yele = false;
}
}
};
saxParser.parse("c:\\input.xml", handler);
} catch (Exception e) {
e.printStackTrace();
}
Thanks
You can declare arrays to hold the values of X and Y and an index to increment after storing the values every time characters method is called by the parser, in your DefaultHandler implementation and expose these arrays through getters. Alternatively, you can use collections like java.util.List/java.util.ArrayList to hold the values.
public static void main(String argv[])
{
try
{
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
MyDefaultHandler handler = new MyDefaultHandler();
saxParser.parse("c:\\input.xml", handler);
System.out.println(handler.getXList() + ", " + handler.getYList());
}
catch (Exception e)
{
e.printStackTrace();
}
}
static class MyDefaultHandler extends DefaultHandler
{
private List<Integer> xList = new ArrayList<Integer>();
private List<Integer> yList = new ArrayList<Integer>();
boolean xele = false;
boolean yele = false;
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
if (qName.equalsIgnoreCase("X"))
{
xele = true;
}
if (qName.equalsIgnoreCase("Y"))
{
yele = true;
}
}
public void characters(char ch[], int start, int length) throws SAXException
{
if (xele)
{
System.out.println("X value : " + new String(ch, start, length));
xele = false;
xList.add(Integer.parseInt(new String(ch, start, length)));
}
if (yele)
{
System.out.println("Y value : " + new String(ch, start, length));
yele = false;
yList.add(Integer.parseInt(new String(ch, start, length)));
}
}
public List<Integer> getXList()
{
return xList;
}
public List<Integer> getYList()
{
return yList;
}
};
I am trying to parse a UTF-8 xml file using SAX parser and i used the parser but it results an exception it's message "Expecting an element"
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<config>
<filepath>/mnt/sdcard/Audio_Recorder/anonymous22242.3gp</filepath>
<filename>anonymous22242.3gp</filename>
<annotation>
<file>anonymous22242.3gp</file>
<timestamp>0:06</timestamp>
<note>test1</note>
</annotation>
<annotation>
<file>anonymous22242.3gp</file>
<timestamp>0:09</timestamp>
<note>لول</note>
</annotation>
<annotation>
<file>anonymous22242.3gp</file>
<timestamp>0:09</timestamp>
<note>لولو</note>
</annotation>
</config>
private static String fileDirectory;
private final static ArrayList<String> allFileNames = new ArrayList<String>();
private final static ArrayList<String[]> allAnnotations = new ArrayList<String[]>();
private static String[] currentAnnotation = new String[3];
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser playbackParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
boolean audioFullPath = false;
boolean audioName = false;
boolean annotationFile = false;
boolean annotationTimestamp = false;
boolean annotationNote = false;
public void startElement(String uri, String localName,
String qName, Attributes attributes)
throws SAXException {
System.out.println("Start Element :" + qName);
if (qName.equalsIgnoreCase("filepath")) {
audioFullPath = true;
}
if (qName.equalsIgnoreCase("filename")) {
audioName = true;
}
if (qName.equalsIgnoreCase("file")) {
annotationFile = true;
}
if (qName.equalsIgnoreCase("timestamp")) {
annotationTimestamp = true;
}
if (qName.equalsIgnoreCase("note")) {
annotationNote = true;
}
}
public void endElement(String uri, String localName,
String qName) throws SAXException {
System.out.println("End Element :" + qName);
}
public void characters(char ch[], int start, int length)
throws SAXException {
if (audioFullPath) {
String filePath = new String(ch, start, length);
System.out.println("Full Path : " + filePath);
fileDirectory = filePath;
audioFullPath = false;
}
if (audioName) {
String fileName = new String(ch, start, length);
System.out.println("File Name : " + fileName);
allFileNames.add(fileName);
audioName = false;
}
if (annotationFile) {
String fileName = new String(ch, start, length);
currentAnnotation[0] = fileName;
annotationFile = false;
}
if (annotationTimestamp) {
String timestamp = new String(ch, start, length);
currentAnnotation[1] = timestamp;
annotationTimestamp = false;
}
if (annotationNote) {
String note = new String(ch, start, length);
currentAnnotation[2] = note;
annotationNote = false;
allAnnotations.add(currentAnnotation);
}
}
};
InputStream inputStream = getStream("http://www.example.com/example.xml");
Reader xmlReader = new InputStreamReader(inputStream, "UTF-8");
InputSource xmlSource = new InputSource(xmlReader);
xmlSource.setEncoding("UTF-8");
playbackParser.parse(xmlSource, handler);
System.out.println(fileDirectory);
System.out.println(allFileNames);
System.out.println(allAnnotations);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public Static InputStream getStream(String url)
{
try
{
connection = getConnection(url);
connection.setRequestProperty("User-Agent",System.getProperty("microedition.profiles"));
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");
inputStream = connection.openInputStream();
return inputStream;
}
catch(Exception e)
{
System.out.println("NNNNNNN "+e.getMessage());
return null;
}
}
public HttpConnection getConnection(String url)
{
try
{
connection = (HttpConnection) Connector.open(url+getConnectionString());
}
catch(Exception e)
{
}
return connection;
}
but when i pass to the parse method the inputStream instead of inputSource it parses the file but still have a problem with Arabic characters between
playbackParser.parse(inputStream, handler);
The XML you showed has unencoded Arabic characters in it. That is in violation of the XML's declared Encoding, which means the XML is malformed. A SAX parser processes data piece by piece sequentially, triggering events for each piece. It will not detect such an encoding error until it reaches the piece that contains those erroneous characters. There is nothing you can do about that. The XML needs to be fixed by its original author.