【问题标题】:Control code 0x6 causing XML error控制代码 0x6 导致 XML 错误
【发布时间】:2012-01-06 04:21:56
【问题描述】:

我有一个 Java 应用程序正在运行,它通过 XML 获取数据,但有时我有一些包含某种控制代码的数据?

An invalid XML character (Unicode: 0x6) was found in the CDATA section.
org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0x6) was found in     the CDATA section.
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    at domain.Main.processLogFromUrl(Main.java:342)
    at domain.Main.<init>(Main.java:67)
    at domain.Main.main(Main.java:577)

由于我找不到太多信息,谁能解释这个控制代码的确切作用?

提前致谢。

【问题讨论】:

  • Java 没有错,您的 XML 源文件已损坏,您需要与负责创建它的人交谈以修复它。背景的类似问题:stackoverflow.com/questions/2622552/…
  • 如果您不期望 Unicode 字符,而 UTF-8 是您通常得到的,那么是谁在响应中添加了 Unicode 字符?
  • @djangofan,负责数据的网络服务正在检查他们的系统,它几乎每月发生一次。

标签: java xml unicode saxparser


【解决方案1】:

您需要编写FilterInputStream 以在 SAX 解析器获取数据之前过滤数据。它必须删除或重新编码不良数据。

Apache 有一个super-flexible 示例。您可能希望组装一个更简单的。

这是我的一个,它可以做其他清理工作,但我相信这将是一个好的开始。

/* Cleans up often very bad xml. 
 * 
 * 1. Strips leading white space.
 * 2. Recodes &pound; etc to &#...;.
 * 3. Recodes lone & as &amp.
 * 
 */
public class XMLInputStream extends FilterInputStream {

  private static final int MIN_LENGTH = 2;
  // Everything we've read.
  StringBuilder red = new StringBuilder();
  // Data I have pushed back.
  StringBuilder pushBack = new StringBuilder();
  // How much we've given them.
  int given = 0;
  // How much we've read.
  int pulled = 0;

  public XMLInputStream(InputStream in) {
    super(in);
  }

  public int length() {
    // NB: This is a Troll length (i.e. it goes 1, 2, many) so 2 actually means "at least 2"

    try {
      StringBuilder s = read(MIN_LENGTH);
      pushBack.append(s);
      return s.length();
    } catch (IOException ex) {
      log.warning("Oops ", ex);
    }
    return 0;
  }

  private StringBuilder read(int n) throws IOException {
    // Input stream finished?
    boolean eof = false;
    // Read that many.
    StringBuilder s = new StringBuilder(n);
    while (s.length() < n && !eof) {
      // Always get from the pushBack buffer.
      if (pushBack.length() == 0) {
        // Read something from the stream into pushBack.
        eof = readIntoPushBack();
      }

      // Pushback only contains deliverable codes.
      if (pushBack.length() > 0) {
        // Grab one character
        s.append(pushBack.charAt(0));
        // Remove it from pushBack
        pushBack.deleteCharAt(0);
      }

    }
    return s;
  }

  // Returns false at eof.
  // Might not actually push back anything but usually will.
  private boolean readIntoPushBack() throws IOException {
    // File finished?
    boolean eof = false;
    // Next char.
    int ch = in.read();
    if (ch >= 0) {
      // Discard whitespace at start?
      if (!(pulled == 0 && isWhiteSpace(ch))) {
        // Good code.
        pulled += 1;
        // Parse out the &stuff;
        if (ch == '&') {
          // Process the &
          readAmpersand();
        } else {
          // Not an '&', just append.
          pushBack.append((char) ch);
        }
      }
    } else {
      // Hit end of file.
      eof = true;
    }
    return eof;
  }

  // Deal with an ampersand in the stream.
  private void readAmpersand() throws IOException {
    // Read the whole word, up to and including the ;
    StringBuilder reference = new StringBuilder();
    int ch;
    // Should end in a ';'
    for (ch = in.read(); isAlphaNumeric(ch); ch = in.read()) {
      reference.append((char) ch);
    }
    // Did we tidily finish?
    if (ch == ';') {
      // Yes! Translate it into a &#nnn; code.
      String code = XML.hash(reference);
      if (code != null) {
        // Keep it.
        pushBack.append(code);
      } else {
        throw new IOException("Invalid/Unknown reference '&" + reference + ";'");
      }
    } else {
      // Did not terminate properly! 
      // Perhaps an & on its own or a malformed reference.
      // Either way, escape the &
      pushBack.append("&amp;").append(reference).append((char) ch);
    }
  }

  private void given(CharSequence s, int wanted, int got) {
    // Keep track of what we've given them.
    red.append(s);
    given += got;
    log.finer("Given: [" + wanted + "," + got + "]-" + s);
  }

  @Override
  public int read() throws IOException {
    StringBuilder s = read(1);
    given(s, 1, 1);
    return s.length() > 0 ? s.charAt(0) : -1;
  }

  @Override
  public int read(byte[] data, int offset, int length) throws IOException {
    int n = 0;
    StringBuilder s = read(length);
    for (int i = 0; i < Math.min(length, s.length()); i++) {
      data[offset + i] = (byte) s.charAt(i);
      n += 1;
    }
    given(s, length, n);
    return n > 0 ? n : -1;
  }

  @Override
  public String toString() {
    String s = red.toString();
    String h = "";
    // Hex dump the small ones.
    if (s.length() < 8) {
      Separator sep = new Separator(" ");
      for (int i = 0; i < s.length(); i++) {
        h += sep.sep() + Integer.toHexString(s.charAt(i));
      }
    }
    return "[" + given + "]-\"" + s + "\"" + (h.length() > 0 ? " (" + h + ")" : "");
  }

  private boolean isWhiteSpace(int ch) {
    switch (ch) {
      case ' ':
      case '\r':
      case '\n':
      case '\t':
        return true;
    }
    return false;
  }

  private boolean isAlphaNumeric(int ch) {
    return ('a' <= ch && ch <= 'z') 
        || ('A' <= ch && ch <= 'Z') 
        || ('0' <= ch && ch <= '9');
  }
}

【讨论】:

    【解决方案2】:

    你为什么得到这个字符将取决于数据要代表什么。 (显然是ACK,但在文件中表示这很奇怪......)然而,重要的是它使 XML 无效 - 您根本无法在 XML 中表示该字符。

    来自XML 1.0 specsection 2.2

    字符范围

    /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
    Char       ::=   #x9 | #xA | #xD | [#x20-#xD7FF] 
                         | [#xE000-#xFFFD] | [#x10000-#x10FFFF] 
    

    注意这如何排除 U+0020 以下的 Unicode 值,而不是 U+0009(制表符)、U+000A(换行)和 U+000D(回车)。

    如果您对返回的数据有任何影响,则应将其更改为返回有效的 XML。如果没有,您必须在将其解析为 XML 之前对其进行一些预处理。您想要对不需要的控制字符做什么取决于它们在您的情况下的含义。

    【讨论】:

      【解决方案3】:

      尝试将您的 XML 定义为 1.1 版:

      <?xml version="1.1"?>
      

      【讨论】:

      • 无济于事。控制字符在 XML 1.1 中也受到限制。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-25
      • 1970-01-01
      • 2016-06-09
      • 1970-01-01
      • 2017-02-08
      相关资源
      最近更新 更多