Java Xml Element - Get node position in the file - java

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);

Related

java parser sax doesn't get value & on my field

I have more elements on my xml file contains & and others characters html >.
I tested my code but it obtain the first part of my field for example:
SERIES & FILMS
It give only the word SERIES.
And other example:
C>SUDO
It give only C.
My code, my field name is "summary":
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
chars = new StringBuffer();
DefaultHandler handler = new DefaultHandler() {
public void startElement(String uri, String localName,
String qName, Attributes attributes)
throws SAXException {
System.out.println("Start Element :" + qName);
if (qName.equals(SUMMARY2)) {
bfSummary = true;
}
if (qName.equals(SERVICE_DATA)) {
idServiceData = attributes.getValue("id");
bfServicedata = true;
}
}
public void endElement(String uri, String localName,
String qName) throws SAXException {
System.out.println("End Element :" + qName + ""
+ mListBaseLineByEpgId.size());
// maliste.put(listeId, summary);
malisteParThem.add(summary);
if (mListBaseLineByEpgId.get(idServiceData) != null) {
List<String> listeModif = mListBaseLineByEpgId
.get(idServiceData);
for (String chaine : malisteParThem) {
listeModif.add(chaine);
}
mListBaseLineByEpgId.replace(idServiceData, listeModif);
} else {
mListBaseLineByEpgId.put(idServiceData, malisteParThem);
}
malisteParThem = new ArrayList<String>();
}
public void characters(char ch[], int start, int length)
throws SAXException {
if (bfSummary) {
summary = new String(ch, start, length);
summary = summary.replace(BEFORETILESUMMARY, "");
// chars.append(summary);
// summary=chars.toString();
summary = removeHtmlFrom(summary);
System.out.println("Summary : " + summary);
bfSummary = false;
}
if (bfServicedata) {
System.out.println("listeId : " + idServiceData);
bfServicedata = false;
}
}
};
File file = new File(cheminFichier);
InputStream inputStream = new FileInputStream(file);
Reader reader = new InputStreamReader(inputStream);
InputSource is = new InputSource(reader);
//is.setEncoding("ISO-8859-1");
saxParser.parse(is, handler);
} catch (Exception e) {
e.printStackTrace();
}
Thank you.
Perhaps this problem is related to the unexpected behavior of SAX parser: it is allowed (per spec) to split the text part of an element and call characters() method multiple times for the same element.
What you need to do is have a StringBuffer or StringBuilder instance variable. You initialize it in startElement(), append to it on characters() and get the full text on endElement()
see this question for more info JAVA SAX parser split calls to characters()

Can't parse File and Handler in SAXParser

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.

RSS Parser returns 403

I'm new to Java and we were given an assignment about XML Parsing. We have done DOM and now we are on SAX. That's why I'm using SAX Parser for parsing an rss feed. Its already working on files but when I try to parse an online rss feed, it returns an Error 403. I haven't tried parsing the same site on DOM because my laptop is so slow it takes me 5 minutes just to open a file.
Thanks for the help.
public class NewsHandler extends DefaultHandler {
private String url = "http://tomasinoweb.org/feed/rss";
private boolean inDescription = false;
private String[] descs = new String[11];
int i = 0;
public void processFeed() {
try {
SAXParserFactory factory =
SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader reader = parser.getXMLReader();
reader.setContentHandler(this);
InputStream inputStream = new URL(url).openStream();
reader.parse(new InputSource(inputStream));
} catch (Exception e) { e.printStackTrace(); }
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(qName.equals("description")) inDescription = true;
}
public void characters(char ch[], int start, int length) {
String chars = new String(ch).substring(start, start + length);
if(inDescription) descs[i] = chars;
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if(qName.equals("description")) {
inDescription = false;
i++;
}
}
public String getDesc(int index) { return descs[index]; }
public static void main(String[] args) {
NewsHandler nh = new NewsHandler();
nh.processFeed();
for(int i=0; i<10; i++) {
System.out.println(nh.getDesc(i));
}
}
}
Solution:
Instead of using String url = "url", I used URL url = new URL("url") and URLConnection con = url.openConnection() and then con.addRequestProperty("user-agent", user-agent string);

parse XML and convert to a Collection

<inputs>
<MAT_NO>123</MAT_NO>
<MAT_NO>323</MAT_NO>
<MAT_NO>4223</MAT_NO>
<FOO_BAR>122</FOO_BAR>
<FOO_BAR>125</FOO_BAR>
</inputs>
I've to parse the above the XML. After parsing, i want the values to be in a Map<String, List<String>> with Key values corresponding to the child nodes - MAT_NO, FOO_BAR
and values - the values of the child nodes -123, 323 etc.
Following is my shot. Is there any better way of doing this??
public class UserInputsXmlParser extends DefaultHandler {
private final SaveSubscriptionValues subscriptionValues = null;
private String nodeValue = "";
private final String inputKey = "";
private final List<String> valuesList = null;
private Map<String, List<String>> userInputs;
public Map<String, List<String>> parse(final String strXML) {
try {
final SAXParserFactory parserFactory = SAXParserFactory
.newInstance();
final SAXParser saxParser = parserFactory.newSAXParser();
saxParser.parse(new InputSource(new StringReader(strXML)), this);
return userInputs;
} catch (final SAXException e) {
e.printStackTrace();
throw new MyException("", e);
} catch (final IOException e) {
e.printStackTrace();
throw new MyException("", e);
} catch (final ParserConfigurationException e) {
e.printStackTrace();
throw new MyException("", e);
} catch (final Exception e) {
e.printStackTrace();
throw new MyException("", e);
}
}
#Override
public void startElement(final String uri, final String localName,
final String qName, final Attributes attributes)
throws SAXException {
nodeValue = "";
if ("inputs".equalsIgnoreCase(qName)) {
userInputs = MyUtil.getNewHashMap();
return;
}
}
#Override
public void characters(final char[] ch, final int start, final int length)
throws SAXException {
if (!MyUtil.isEmpty(nodeValue)) {
nodeValue += new String(ch, start, length);
} else {
nodeValue = new String(ch, start, length);
}
}
#Override
public void endElement(final String uri, final String localName,
final String qName) throws SAXException {
if (!"inputs".equalsIgnoreCase(qName)) {
storeUserInputs(qName, nodeValue);
}
}
/**
* #param qName
* #param nodeValue2
*/
private void storeUserInputs(final String qName, final String nodeValue2) {
if (nodeValue2 == null || nodeValue2.trim().equals("")) { return; }
final String trimmedValue = nodeValue2.trim();
final List<String> values = userInputs.get(qName);
if (values != null) {
values.add(trimmedValue);
} else {
final List<String> valueList = new ArrayList<String>();
valueList.add(trimmedValue);
userInputs.put(qName, valueList);
}
}
public static void main(final String[] args) {
final String sample = "<inputs>" + "<MAT_NO>154400-0000</MAT_NO>"
+ "<MAT_NO> </MAT_NO>" + "<MAT_NO>154400-0002</MAT_NO>"
+ "<PAT_NO>123</PAT_NO><PAT_NO>1111</PAT_NO></inputs>";
System.out.println(new UserInputsXmlParser().parse(sample));
}
}
UPDATE: The children of <inputs> nodes are dynamic. I'll be knowing just the root node.
Do you have to provide a solution as part of a SAX event handler? If not then you could use one of the many XML libraries around, such as dom4j. Make the solution a lot simpler;
public static void main(String[] args) throws Exception
{
String sample = "<inputs>" + "<MAT_NO>154400-0000</MAT_NO>"
+ "<MAT_NO> </MAT_NO>" + "<MAT_NO>154400-0002</MAT_NO>"
+ "<PAT_NO>123</PAT_NO><PAT_NO>1111</PAT_NO></inputs>";
System.out.println(parse(sample));
}
static Map<String,List<String>> parse(String xml) throws Exception
{
Map<String,List<String>> map = new HashMap<String,List<String>>();
SAXReader reader = new SAXReader();
Document doc = reader.read(new StringReader(xml));
for (Iterator i = doc.getRootElement().elements().iterator(); i.hasNext();)
{
Element element = (Element)i.next();
//Maybe handle elements with only whitespace text content
List<String> list = map.get(element.getName());
if (list == null)
{
list = new ArrayList<String>();
map.put(element.getName(), list);
}
list.add(element.getText());
}
return map;
}
I would check xstream....( http://x-stream.github.io/tutorial.html )
XStream is a simple library to serialize objects to XML and back again.
For something this basic, look into xpath.

Can't add a value to ArrayList because it's in an Inner Class?

I am writing a file that can parse rdf and owl files. I am using SAX and Java.
My problem is on the line activeObject.add(file);
I get the error "Syntax error on tokens, Misplaced construct(s)" - I don't know what this means. And it doesn't seem to make sense, any help would be much appreciated.
PS: I might be completely wrong about what is causing the error, it might have nothing to do with an inner class.
public static void main(String args[]) throws URISyntaxException, MalformedURLException, IOException {
// String file =
// "http://www.srdc.metu.edu.tr/ubl/contextOntology/cpc.owl";
// final String file = "http://onto.eva.mpg.de/obo/image.owl";
// final String file =
// "http://www.informatik.uni-ulm.de/ki/Liebig/owl/SUMO-LiteTB.rdf";
// final String file =
// "http://www.csd.abdn.ac.uk/~apreece/research/TowardsAnIntelligentWeb/PUB_findallbyKen_result.rdf";
// final String file =
// "http://www.srdc.metu.edu.tr/ubl/contextOntology/naics.owl";
final String file = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
URI uri = new URI(file);
InputStream is = uri.toURL().openStream();
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
ArrayList<String> activeProperty = new ArrayList<String>();
ArrayList<Triple> triplesList = new ArrayList<Triple>();
ArrayList<String> activeObject = new ArrayList<String>();
boolean name = false;
activeObject.add(file);
public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {
activeProperty.add(qName);
int attrLength = attributes.getLength();
for (int i = 0; i < attrLength; i++) {
String attrName = attributes.getQName(i).toLowerCase();
String attrValue = attributes.getValue(i).toLowerCase();
if (attrName.equals("rdf:about") || attrName.equals("rdf:resource") || attrName.equals("rdf:id")) {
activeObject.add(attrValue);
System.out.println(activeObject);
}
else{
String subject = activeObject.get(activeObject.size()-1);
String predicate = attrName;
String object = attrValue;
Triple newTriple = new Triple(subject, predicate, object);
}
}
}
public void characters(char[] ch, int start, int length) throws SAXException {
// tempVal = new String(ch, start, length);
}
public void endElement(String uri, String localName, String rawName) {
String subject = activeObject.get(activeObject.size()-2);
String predicate = activeProperty.get(activeProperty.size()-1);
String object = activeObject.get(activeObject.size()-1);
Triple newTriple = new Triple(subject,predicate, object);
if (rawName.equals(activeProperty.get(activeProperty.size() - 1))) {
activeProperty.remove(activeProperty.size() - 1);
}
else{
System.out.println("Something is seriosuly wrong ...sdf.sdf.we8ryw98fsydh");
}
// System.out.println(activeProperty);
}
// if (qName.equalsIgnoreCase("NAME")) {
// name = true;
// }
// public void characters(char ch[], int start, int length)
// throws SAXException {
// if (name) {
// System.out.println("Name: "
// + new String(ch, start, length));
// name = false;
// }
// }
};
saxParser.parse(is, handler);
} catch (Exception e) {
e.printStackTrace();
}
}
You're trying to write normal statements within an anonymous class, as if you'd tried this:
class Foo extends DefaultHandler {
ArrayList<String> activeProperty = new ArrayList<String>();
ArrayList<Triple> triplesList = new ArrayList<Triple>();
ArrayList<String> activeObject = new ArrayList<String>();
boolean name = false;
activeObject.add(file);
}
You can't do that. If you want this to be performed on construction, you can put it in an initializer block, like this:
ArrayList<String> activeProperty = new ArrayList<String>();
ArrayList<Triple> triplesList = new ArrayList<Triple>();
ArrayList<String> activeObject = new ArrayList<String>();
boolean name = false;
{
activeObject.add(file);
}
Or you could populate the list in some other way, perhaps - for instance with Guava you could write:
ArrayList<String> activeObject = Lists.newArrayList(file);

Categories

Resources