Re: java get xml file line number for the current node
On 2/20/2012 9:32 AM, Arne Vajh?j wrote:
On 2/20/2012 5:50 AM, mani wrote:
How can I now find the line number in the source XML file where this
node occurs?
Using what parser? W3C DOM? SAX? StAX? JDOM?
If we assume:
- you use W3C DOM
- you only need line number for element nodes
- you really need it
- you are willing to write some ugly hacks
then try something like:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class ParseWithLineNumbers {
public static Document parseNormal(String fnm) throws
ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(new File(fnm));
}
public static Document parseSpecial(String fnm) throws
ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(new InputSource(new SpecialReader(fnm)));
}
public static void print(Document doc) throws ClassCastException,
ClassNotFoundException, InstantiationException, IllegalAccessException {
DOMImplementation impl =
DOMImplementationRegistry.newInstance().getDOMImplementation("XML 3.0");
DOMImplementationLS feature =
(DOMImplementationLS)impl.getFeature("LS","3.0");
LSSerializer ser = feature.createLSSerializer();
LSOutput output = feature.createLSOutput();
output.setByteStream(System.out);
ser.write(doc, output);
}
public static void main(String[] args) throws Exception {
Document d1 = parseNormal("test.xml");
print(d1);
Document d2 = parseSpecial("test.xml");
print(d2);
}
}
class SpecialReader extends FileReader {
private int lineno;
private boolean inelm;
private boolean eof;
private Queue<Character> extra;
public SpecialReader(String fnm) throws FileNotFoundException {
super(fnm);
lineno = 1;
inelm = false;
eof = false;
extra = new LinkedList<Character>();
}
@Override
public int read(char[] ch, int ix, int n) throws IOException {
if(eof) return -1;
int res = 0;
wloop:
while(res < n) {
int c = extra.isEmpty() ? super.read() : extra.remove();
if(inelm && (c == ' ' || c == '>')) {
for(char xc : (" lineno='" + lineno +"'").toCharArray()) {
extra.add(xc);
}
extra.add((char)c);
c = extra.remove();
inelm = false;
}
switch(c) {
case '\n' :
lineno++;
break;
case '<' :
inelm = true;
break;
case '/':
inelm = false;
break;
case -1 :
eof = true;
break wloop;
default:
/* nothing */
break;
}
ch[ix + res] = (char)c;
res++;
}
return res;
}
}
It adds an attribute lineno to all elment nodes.
Arne