从xml节点获取行号-java
我解析了一个XML文件,得到了一个我感兴趣的节点。现在如何在该节点所在的源XML文件中找到行号 编辑: 目前我正在使用SAXParser来解析我的XML。不过,我很乐意使用任何解析器的解决方案 除了节点之外,我还有节点的XPath表达式从xml节点获取行号-java,java,xml,Java,Xml,我解析了一个XML文件,得到了一个我感兴趣的节点。现在如何在该节点所在的源XML文件中找到行号 编辑: 目前我正在使用SAXParser来解析我的XML。不过,我很乐意使用任何解析器的解决方案 除了节点之外,我还有节点的XPath表达式 我需要获取行号,因为我正在文本框中显示XML文件,并且需要突出显示节点所在的行。假设XML文件格式良好,有足够的换行符。如果使用SAX解析器,则可以使用Locator对象获取事件的行号,该对象通过setDocumentLocator回调通知ContentHand
我需要获取行号,因为我正在文本框中显示XML文件,并且需要突出显示节点所在的行。假设XML文件格式良好,有足够的换行符。如果使用SAX解析器,则可以使用Locator对象获取事件的行号,该对象通过setDocumentLocator回调通知ContentHandler。这是在解析开始时调用的,您需要保存定位器;然后在任何事件(如startElement)之后,可以调用getLineNumber等方法来获取源文件中的当前位置。startElement之后,回调被定义为提供开始标记的>出现的行号。我通过以下示例实现了这一点: 此解决方案遵循Michael Kay建议的方法。以下是您如何使用它:
// XmlTest.java
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
public class XmlTest {
public static void main(final String[] args) throws Exception {
String xmlString = "<foo>\n"
+ " <bar>\n"
+ " <moo>Hello World!</moo>\n"
+ " </bar>\n"
+ "</foo>";
InputStream is = new ByteArrayInputStream(xmlString.getBytes());
Document doc = PositionalXMLReader.readXML(is);
is.close();
Node node = doc.getElementsByTagName("moo").item(0);
System.out.println("Line number: " + node.getUserData("lineNumber"));
}
}
如果你运行这个程序,它将输出:行号:3
PositionXmlReader是上面链接的示例的一个稍加修改的版本
// PositionalXMLReader.java
import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class PositionalXMLReader {
final static String LINE_NUMBER_KEY_NAME = "lineNumber";
public static Document readXML(final InputStream is) throws IOException, SAXException {
final Document doc;
SAXParser parser;
try {
final SAXParserFactory factory = SAXParserFactory.newInstance();
parser = factory.newSAXParser();
final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
final DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
doc = docBuilder.newDocument();
} catch (final ParserConfigurationException e) {
throw new RuntimeException("Can't create SAX parser / DOM builder.", e);
}
final Stack<Element> elementStack = new Stack<Element>();
final StringBuilder textBuffer = new StringBuilder();
final DefaultHandler handler = new DefaultHandler() {
private Locator locator;
@Override
public void setDocumentLocator(final Locator locator) {
this.locator = locator; // Save the locator, so that it can be used later for line tracking when traversing nodes.
}
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes)
throws SAXException {
addTextIfNeeded();
final Element el = doc.createElement(qName);
for (int i = 0; i < attributes.getLength(); i++) {
el.setAttribute(attributes.getQName(i), attributes.getValue(i));
}
el.setUserData(LINE_NUMBER_KEY_NAME, String.valueOf(this.locator.getLineNumber()), null);
elementStack.push(el);
}
@Override
public void endElement(final String uri, final String localName, final String qName) {
addTextIfNeeded();
final Element closedEl = elementStack.pop();
if (elementStack.isEmpty()) { // Is this the root element?
doc.appendChild(closedEl);
} else {
final Element parentEl = elementStack.peek();
parentEl.appendChild(closedEl);
}
}
@Override
public void characters(final char ch[], final int start, final int length) throws SAXException {
textBuffer.append(ch, start, length);
}
// Outputs text accumulated under the current node
private void addTextIfNeeded() {
if (textBuffer.length() > 0) {
final Element el = elementStack.peek();
final Node textNode = doc.createTextNode(textBuffer.toString());
el.appendChild(textNode);
textBuffer.delete(0, textBuffer.length());
}
}
};
parser.parse(is, handler);
return doc;
}
}
注意,根据Locator.getLineNumber的规范,该方法返回SAX事件结束的行号 对于startElement,这意味着: 此处元素的行号为1: 此处元素的行号为3: 答案很好,很有效。对于我的用例,我需要将它集成到一个现有的框架中,例如编码也在其中。因此,应用了以下重构以拥有一个单独的LineNumberHandler类 然后,该代码还将与Sax InputSource一起使用,其中编码可以修改如下:
// read in the xml document
org.xml.sax.InputSource is=new org.xml.sax.InputSource();
is.setByteStream(instream);
if (encoding!=null) {
is.setEncoding(encoding);
if (Debug.CORE)
Debug.log("setting XML encoding to - "+is.getEncoding());
}
独立行号处理程序
/**
*行号处理程序
*@author wf
*
*/
公共静态类LineNumberHandler扩展了DefaultHandler{
最终堆栈元素堆栈=新堆栈;
最终StringBuilder textBuffer=新StringBuilder;
专用定位器;
私人文件文件;
/**
*为给定文档创建行号处理程序
*@param doc
*/
公共行号HandlerDocument文档{
this.doc=doc;
}
@凌驾
公共无效集合文档定位器最终定位器{
this.locator=locator;//保存定位器,以便使用
//稍后用于遍历时的线跟踪
//节点。
}
@凌驾
public void startElementfinal字符串uri、final字符串localName、,
最终字符串qName,最终属性引发SAXException{
添加文本(如果需要);
最终元素el=doc.createElementqName;
对于int i=0;i请注意,此解决方案只注意元素,忽略注释,也可能忽略CDATA和DTD。您可以按照javadoc的指示实现并调用setProperty来实现这些。您好,我可以配置saxon XSLT处理器作为特定xml解析器的任何版本吗?我只找到参数-x来使用自己的SAX解析器。Saxon有一个配置选项-l或FeatureKeys.LINE_编号,这将使它收集XML解析器提供的行号信息,并将其保留在构造的树中。然后可以使用saxon:line number扩展函数访问它。谢谢您的回答。我知道萨克森:行号函数。对不起,我做得不够精确!priomsrb的答案促使我修改他的位置XmlReader,以便向节点添加更多用户数据。我发现saxon:getUserData函数只适用于<7.4?我想知道是否可以用它直接将更多关于节点的信息输入XSLT。EGth的最后一行/列编号
我建议您在saxonica.plan.io的论坛上详细描述一下您想要做什么。这似乎有点太复杂,无法在这里的评论线程中处理。Hello@hhaehle。欢迎来到SO。这是一些有用的信息,但可能应该放在评论中,因为它没有回答原始问题。您可以了解更多有关评论的信息。因此行号是结束行号,但是有没有办法获取事件开始的起始行?
<Element
attribute1="X"
attribute2="Y">
</Element>
// read in the xml document
org.xml.sax.InputSource is=new org.xml.sax.InputSource();
is.setByteStream(instream);
if (encoding!=null) {
is.setEncoding(encoding);
if (Debug.CORE)
Debug.log("setting XML encoding to - "+is.getEncoding());
}
public class PositionalXMLReader {
final static String LINE_NUMBER_KEY_NAME = "lineNumber";
/**
* read a document from the given input strem
*
* @param is
* - the input stream
* @return - the Document
* @throws IOException
* @throws SAXException
*/
public static Document readXML(final InputStream is)
throws IOException, SAXException {
final Document doc;
SAXParser parser;
try {
final SAXParserFactory factory = SAXParserFactory.newInstance();
parser = factory.newSAXParser();
final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
.newInstance();
final DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
doc = docBuilder.newDocument();
} catch (final ParserConfigurationException e) {
throw new RuntimeException("Can't create SAX parser / DOM builder.", e);
}
LineNumberHandler handler = new LineNumberHandler(doc);
parser.parse(is, handler);
return doc;
}
}
package com.bitplan.common.impl;
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import com.bitplan.bobase.PositionalXMLReader;
public class TestXMLWithLineNumbers {
/**
* get an Example XML Stream
* @return the example stream
*/
public InputStream getExampleXMLStream() {
String xmlString = "<foo>\n" + " <bar>\n"
+ " <moo>Hello World!</moo>\n" + " </bar>\n" + "</foo>";
InputStream is = new ByteArrayInputStream(xmlString.getBytes());
return is;
}
@Test
public void testXMLWithLineNumbers() throws Exception {
InputStream is = this.getExampleXMLStream();
Document doc = PositionalXMLReader.readXML(is);
is.close();
Node node = doc.getElementsByTagName("moo").item(0);
assertEquals("3", node.getUserData("lineNumber"));
}
}