JAVA SAX解析器拆分调用字符()

我正在做一个解析XML中的一些数据的项目。

例如,XML就是

abcdefghijklmno 

我需要解析“abcdefghijkmnlp”。

但是当我测试我的解析时,我发现了一个大问题:

 public class parser{ private boolean hasABC = false; //Constructor HERE ...................... ...................... @Override public void startDocument () throws SAXException{ } @Override public void endDocument () throws SAXException{ } @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException{ if ("abc".equalsIgnoreCase(localName)) { this.hasABC = true; } } @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException{ if ("abc".equalsIgnoreCase(localName)) { this.hasABC = false; } } @Override public void characters(char ch[], int start, int length){ String content = new String(ch, start, length).trim(); if(this.hasABC){ System.out.println("ABC = " + content); } } } 

我发现解析器已经解析了两次系统打印输出的标签,

ABC = abcdefghi

ABC = jklmno << ============拆分消息

为什么解析器自动回调字符()两次????

XML是否有一些“\ n”或“\ r”?

解析器不止一次调用characters方法,因为它可以并且允许每个规范。 这有助于快速解析并保持较低的内存占用。 如果你想要一个字符串在startElement创建一个新的StringBuilder对象并在endElement方法上处理它。

您会感到惊讶,但这是一个记录的行为,即您不能假设解析器将读取并返回单个回调中元素的所有文本数据。 我之前有同样的经历。 您需要编写代码来处理这种情况,或者您可以切换到Stax解析器 。 您可以使用CharArrayWriter在多个回调中累积数据。

请参阅下面的ContentDandler.characters的JavaDoc(…)

解析器将调用此方法来报告每个字符数据块。 SAX解析器可以在一个块中返回所有连续的字符数据,或者它们可以将它分成几个块; 但是,任何单个事件中的所有字符都必须来自同一个外部实体,以便Locator提供有用的信息。

您可以更改开始,结束和字符方法,如:

  • 添加“全局”内容变量
  • 然后在start方法中将其为null(content == null)
  • 在end方法中,你可以println或将该内容字符串添加到某个对象
  • 在字符方法中你可以使if / else:

     if (content == null) { content = new String(ch, start, length); } else { content += new String(ch, start, length); } 

    野蛮的方式(最好用stringbuilder做)但是工作和“字符串”不再分裂。

这是SAX的一个function。 解析器可以拆分文本段并根据需要多次调用您的characters方法。

其原因在于性能,SAX优先于易用性。 SAX可能已经耗尽了它的内部缓冲区,因此为了避免复制,SAX将其迄今为止的数据传递给您的代码。