Xml节点文本在有滑稽字符时会导致问题

时间:2011-12-11 03:17:41

标签: java xml sax xerces

我在以下事件中设置xml元素中的字符:

 public void characters(char[] ch, int start, int length) {
        elementText = new String(ch, start, length);
    }

其中elementText是一个字符串。

<client-key>#&lt;ABC::DEF::GHI:0x102548f78&gt;</client-key>

我将这个xml数据加载到java对象中,我的objects属性具有以下值:

 '\n        '

现在如果我更改上面元素<client-key>中的文本,它在我的对象属性中就可以了。

我是否需要以某种方式处理某些编码问题?

public void endElement(String uri, String localName, String qName) {

       if (qName.equals("client-key")) {
            client.setClientKey(elementText);
        }

}

3 个答案:

答案 0 :(得分:11)

这可能是你的xml整理后的结果:

<client-key>
    #&lt;ABC::DEF::GHI:0x102548f78&gt;
</client-key>

请参阅ContentHandler

  

字符
  ......   解析器将调用此方法来报告每个字符数据块。 SAX解析器可以在一个块中返回所有连续的字符数据,或者它们可以将它分成几个块; ...

你最好使用类似的东西:

public void characters(char[] ch, int start, int length) {
  // Note the +=
  elementText += new String(ch, start, length);
}

public void endElement(String uri, String localName, String qName) {

  if (qName.equals("client-key")) {
    client.setClientKey(elementText);
  }
  elementText = "";
}

答案 1 :(得分:2)

XML解析器通常使用两个阶段来处理文档中的数据。在第一阶段,文档(字节序列)被解码成放置在输入缓冲器中的字符序列。实际的XML解析在第二阶段完成,其中分析了诸如元素开始和结束标记的不同构造。请注意,两个阶段都是并行执行的。更准确地说,随着XML解析的进行,输入缓冲区会根据需要重新填充。另请注意,如果文档已作为字符序列提供(例如使用StringReader),则跳过第一阶段的解码,但解析器仍将使用输入缓冲区来存储从中读取的字符流。

如其他人所述,SAX解析器不需要将文本节点报告为单个块。它可以自行决定将节点分成多个块。这称为非合并解析

你称之为“有趣的人物”实际上是字符实体引用(在你的情况下是&amp; lt;和&amp; gt;)。在将数据发送到应用程序之前,需要对它们进行解码(在您的情况下为'&lt;'和'&gt;')。但是,这只能在第二阶段完成。原因是相同的字符序列(例如'&amp; lt;')可能不需要解码,如果它出现在不同的上下文中,特别是在CDATA部分中。

关键是如果文本节点不包含任何实体引用,则解析器可以将字符数据直接从输入缓冲区传递给应用程序。这增加了将整个文本节点报告为单个块的概率。但是,即使在这种情况下,文本节点也可能不完全适合输入缓冲区,在这种情况下,解析器将以多个块报告它。

另一方面,如果文本节点包含实体引用,则解析器不能将数据直接从输入缓冲区传递给应用程序,因为部分数据需要进一步解码。为了避免多次复制数据,大多数解析器将选择将不需要进一步解码的部分直接传递给应用程序,而实体引用首先被解码为单独的缓冲区。这就是为什么你得到原始文档中的块被实体引用分隔的原因。

答案 2 :(得分:0)

工作正常。但正如他所说,节点的内容有多个块。所以你需要追加它。以下示例显示使用和不使用cdata

的输出
public class XMLTest {

    public static void main(String argv[]) {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser saxParser = factory.newSAXParser();

            DefaultHandler handler = new DefaultHandler() {

                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                }

                public void endElement(String uri, String localName, String qName) throws SAXException {
                }

                public void characters(char ch[], int start, int length) throws SAXException {
                    System.out.println(new String(ch, start, length));
                }
            };
            saxParser.parse("test.xml", handler);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

<?xml version="1.0"?>
<company>
    <staff>
        <client-key>#&lt;ABC::DEF::GHI:0x102548f78&gt;</client-key>    
        <client-key><![CDATA[#<ABC::DEF::GHI:0x102548f78>]]></client-key>    
    </staff>
</company>

输出:

#
<
ABC::DEF::GHI:0x102548f78
>


#<ABC::DEF::GHI:0x102548f78> 

对于第一个客户端密钥标记,您收到的最后一个块是带有一些空格的新行字符。由于你没有追加它,你只能获得带有一些空格的换行符,这是最后一个块。

如果您有正常的角色,它可以正常工作,因为内容没有中断,您可以将它们放在一个块中。

相同的输入:

<client-key>testing</client-key>

输出:

testing

所以要么使用CDATA,要么附加。