【问题标题】:Retrieve XML node by line number and line position in Java在Java中按行号和行位置检索XML节点
【发布时间】:2019-01-14 10:24:52
【问题描述】:

我们正在接收根据规范有效的 XML 文件。有一个外部方检查原始 XML 文件并根据 XML 文件的内容生成警告。如果有警告,这将产生两个文件:

  • 原始 XML 文件。
  • 包含与 XML 文件相关的警告/错误的文件。

问题在于,对于每个警告,它们在原始文件中通过行号和行位置引用该警告。

  <PositionInBericht>
    <LineNumber>78</LineNumber>
    <LinePosition>10</LinePosition>
  </PositionInBericht>

不幸的是,我们无法对其进行任何更改,因为规范中已写明它的行为应该是这样的。我在互联网上搜索示例,但找不到太多符合我要求的示例。

我找到的资源是:

JAVA中如何使用行号和列号获取XML中的元素 How should I use line number and column number to get element in XML in JAVA

Java / Groovy : 按行号查找 XML 节点 Java / Groovy : Find XML node by Line number

这些帖子中提供的解决方案并不理想或不存在。我想知道人们是否曾经这样做过并想出了一个好的解决方案。

编辑:

为了帮助人们,我找到了解决方案。它基本上做了以下事情:指定行号,它会打印出开始元素的信息。

public class ParsingByLineNumberApplication {

/**
 * URL's gebruikt ter inspiratie voor dit project.
 *
 * How should I use line number and column number to get element in XML in JAVA
 * https://stackoverflow.com/questions/41225724/how-should-i-use-line-number-and-column-number-to-get-element-in-xml-in-java
 *
 * Java / Groovy : Find XML node by Line number
 * https://stackoverflow.com/questions/47701357/java-groovy-find-xml-node-by-line-number
 *
 * Parsing XML documents partially with StAX
 * https://www.ibm.com/developerworks/library/x-tipstx2/index.html
 *
 * @param args
 * @throws FileNotFoundException
 * @throws XMLStreamException
 * @throws URISyntaxException
 */
public static void main(String[] args) throws FileNotFoundException, XMLStreamException, URISyntaxException {
    printElementsAtLineNumber(53);
}

private static void printElementsAtLineNumber(int lineNumber) throws URISyntaxException, FileNotFoundException, XMLStreamException {
    URL resource = ParsingByLineNumberApplication.class.getClassLoader().getResource("test_file.XML");
    FileReader reader = new FileReader(new File(resource.toURI()));
    XMLInputFactory factory = XMLInputFactory.newInstance();
    XMLStreamReader xmlr = factory.createXMLStreamReader(reader);

    // Create a filtered stream reader
    XMLStreamReader xmlfr = factory.createFilteredReader(xmlr, filter);

    // Main event loop
    while (xmlfr.hasNext()) {

        // Process single event
        if (xmlfr.getEventType() == XMLStreamConstants.START_ELEMENT) {
            if (lineNumber == xmlfr.getLocation().getLineNumber()) {
                System.out.println("Character offset: " + xmlfr.getLocation().getCharacterOffset());
                System.out.println("Column number: " + xmlfr.getLocation().getColumnNumber());
                System.out.println("Element name: " + xmlfr.getName().getLocalPart());
                System.out.println("Line number: " + xmlr.getLocation().getLineNumber());
                System.out.println("Element text: " + xmlr.getElementText());
            }
        }

        // Move to next event
        xmlfr.next();
    }
}

private static QName[] exclude = new QName[]{
        new QName("invoice"), new QName("item")};

private static StreamFilter filter = new StreamFilter() {
    // Element level
    int depth = -1;
    // Last matching path segment
    int match = -1;
    // Filter result
    boolean process = true;
    // Character position in document
    int currentPos = -1;

    public boolean accept(XMLStreamReader reader) {
        // Get character position
        Location loc = reader.getLocation();
        int pos = loc.getCharacterOffset();
        // Inhibit double execution
        if (pos != currentPos) {
            currentPos = pos;
            switch (reader.getEventType()) {
                case XMLStreamConstants.START_ELEMENT:
                    // Increment element depth
                    if (++depth < exclude.length && match == depth - 1) {
                        // Compare path segment with current element
                        if (reader.getName().equals(exclude[depth]))
                            // Equal - set segment pointer
                            match = depth;
                    }
                    // Process all elements not in path
                    process = match < exclude.length - 1;
                    break;
                // End of XML element
                case XMLStreamConstants.END_ELEMENT:
                    // Process all elements not in path
                    process = match < exclude.length - 1;
                    // Decrement element depth
                    if (--depth < match)
                        // Update segment pointer
                        match = depth;
                    break;
            }
        }
        return process;
    }
};

}

【问题讨论】:

    标签: java xml parsing


    【解决方案1】:

    SAX 解析器显示行号信息; DOM 解析器(以及更高级别的工具,例如 JAXB)通常不会。我不知道你找到这些信息后想对它做什么,但是编写应用程序以使用 SAX 来完成这项工作听起来很辛苦。

    如果您使用 Saxon,那么您可以选择在构建的树中保留行号和列号(Saxon 从 SAX 解析器获取信息并将其保留在树中)。例如,您可以在 s9api 接口中使用 DocumentBuilder.setLineNumbering() 请求此操作。如果您使用的是 XSLT、XPath 或 XQuery,那么您可以使用扩展函数 saxon:line-number()saxon:column-number()(需要 Saxon-PE 或 -EE)来获取信息。您还可以从导航树的 Java 应用程序获取信息。

    请注意,为元素返回的行号和列号是在 SAX 规范中定义的:具体来说,“>”在开始标记末尾的位置。这可能无法准确反映数据文件中给出的行和列。

    【讨论】:

    • 感谢您的意见。输入上述消息后,我继续搜索示例。我偶然发现了 IBM 的一个例子:ibm.com/developerworks/library/x-tipstx2/index.html。我稍微改变了这个例子,我正在对行号和位置进行匹配。我确实需要保存元素的开头和结尾,以便以后处理。这种方法的好处是它在 JDK 中是标准的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    相关资源
    最近更新 更多