XmlSlurper: получение номера строки groovy.util.slurpersupport.NodeChild в исходном файле.
Я использую XmlSlurper для анализа XML-файла для обработки. Мне нужно найти номер строки некоторых критериев соответствия в файле.
Вот что у меня так далеко:
def void findServlets() {
this.servlets = webFile.depthFirst().findAll{
it.name() == 'servlet'
}
println this.servlets
}
Теперь мне нужно найти соответствующий номер строки для каждого соответствующего "сервлета". Используя SaxParser, я бы сделал следующее:
node.getUserData(SaxParser.KEY_LINE_NO)
Как бы я выполнил ту же задачу на GpathResult в Groovy?
Большое спасибо, Майкл
2 ответа
Вы не можете сделать это напрямую, но вы можете украсить каждый элемент анализируемого DOM атрибутом номера строки.
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.ext.Attributes2Impl;
import javax.xml.parsers.ParserConfigurationException;
class MySlurper extends XmlSlurper {
public static final String LINE_NUM_ATTR = "_srmLineNum"
Locator locator
public MySlurper() throws ParserConfigurationException, SAXException {
super();
}
@Override
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Attributes2Impl newAttrs = new Attributes2Impl(attrs);
newAttrs.addAttribute(uri, LINE_NUM_ATTR, LINE_NUM_ATTR, "ENTITY", "" + locator.getLineNumber());
super.startElement(uri, localName, qName, newAttrs);
}
}
def text = '''
<root>
<a>one!</a>
<a>two!</a>
</root>'''
def root = new MySlurper().parseText(text)
root.a.each { println it.@_srmLineNum }
Вот небольшая модификация предложения @preetham. Это позволяет вам установить номера начальной и конечной строк в XML
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.ext.Attributes2Impl;
import javax.xml.parsers.ParserConfigurationException;
class NumberedXmlParser extends XmlSlurper {
public static final String START_LINE = "_start"
public static final String END_LINE = "_end"
Locator locator
// stack and parent are normally private variables in XmlParser
// We create local references to these so that we can hook into them
List<Node> localStack = new ArrayList<Node>();
Node localParent;
public NumberedXmlParser() throws ParserConfigurationException, SAXException {
super();
}
@Override
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
@Override
public void startDocument() throws SAXException {
localParent = null;
super.startDocument();
}
@Override
public void endDocument() throws SAXException {
localStack.clear();
super.endDocument();
}
@Override
public Node createNode(Node parent, Object name, Map attributes) {
// Hack into this method to get access to the parent Node and stack
this.localParent = new Node(parent, name, attributes);
this.localParent["@$START_LINE"] = locator.getLineNumber();
this.localStack.add(this.localParent);
return this.localParent;
}
@Override
public void endElement(final String uri, final String localName, final String qName) {
if (!localStack.isEmpty()) {
Node element = localStack.remove(localStack.size() - 1);
element["@$END_LINE"] = locator.getLineNumber();
if (!localStack.isEmpty()) {
localParent = localStack.get(localStack.size() - 1);
}
}
super.endElement(uri, localName, qName);
}
}