【问题标题】:java sax parser mangles attributes for xml 1.1java sax 解析器破坏 xml 1.1 的属性
【发布时间】:2013-03-16 02:22:21
【问题描述】:

我正在使用 java 的 sax 类来解析 xml 文件。如果 xml 文件显示 1.0 版,一切正常,但如果显示 1.1 版,则 一些 属性会被破坏,给我错误的结果,但不会引发任何异常。

我的xml文件基本上是这样的:

<?xml version="1.1" encoding="UTF-8" ?>
<gpx>
  <trk>
    <name>Name of the track</name>
    <trkseg>
      <trkpt lat="12.3456789" lon="1.2345678">
        <ele>1234</ele>
        <time>2013-03-26T12:34:56Z</time>
        <speed>0</speed>
      </trkpt>
      ... and then 419 further identical copies of this trkpt
    </trkseg>
  </trk>
</gpx>

所以当我使用 sax 解析这个文件时,我期望的是找到 420 个 trkpt 标签,并且每个标签都有 lat 和 lon 属性。特别是,我希望找到 420 个“纬度”属性,它们都是“12.3456789”。

为了解析,我构造了一个处理程序对象并将其提供给这个本地文件的流:

SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
inStream = new FileInputStream(file);
saxParser.parse(inStream, handler);
System.out.println("done");

处理程序类扩展 org.xml.sax.helpers.DefaultHandler 并且只有一个方法 startElement 来响应 trkpt 标签的打开:

public void startElement(String uri, String localName, String qName, Attributes attributes)
{
    if (qName.equals("trkpt") && attributes != null
        && attributes.getLength() == 2
        && attributes.getValue(0).charAt(0) != '1')
    {
        // The trkpt tag has two attributes
        // but the value of the first one doesn't begin with '1'
        System.out.println(attributes.getQName(0) + " = " + attributes.getValue(0));
    }
    super.startElement(uri, localName, qName, attributes);
}

那么结果是什么? 如果 xml 文件的版本为 1.0,那么我看到的只是“完成”。找到了 420 个 trkpt 标签,它们都有两个属性,第一个总是被称为“lat”,这个属性的值总是以“1”开头,正如我所料。太好了!

如果将 xml 文件更改为在第一行指定 version="1.1",那么我会得到以下输出:

lat = :34.56Z</t
lat = :56Z</time
done

所以即使我所有的 420 点都应该相同,但其中两个给了我一个完全错误的属性值。不抛出异常。仍然找到了 420 个 trkpt,它们都有两个属性,称为“lat”和“lon”。奇怪的是,lon 值总是可以的。

我通过直接复制/粘贴第一个 trkpt 在文本编辑器中创建了这个 xml 文件,所以我确信所有的值都是相同的,我确信 xml 文件中没有带有有趣属性值的点,而且我确信该文件没有非 ascii 字符值或实体代码或任何其他奇怪的东西。

我已经在具有两个不同操作系统的三台不同机器上使用 Sun 的 JRE6、OpenJDK6 和 OpenJDK7 进行了尝试。所以要么我做错了什么,要么这个特定的 xml 文件不知何故与 xml1.1 不兼容,或者存在广泛的 sax 错误(这似乎不太可能,因为我认为它会影响很多人)。再次请注意,使用 xml1.0 一切正常。另请注意,数字 420 没有什么特别之处,只是如果文件只有 100 个条目,那么它们都会被正确解析。如果您有数千个条目,那么其中一定数量的条目会以这种方式破坏它们的第一个属性值。属性值的长度似乎总是正确的,但它会从文件中的错误点提取字符。可能是索引溢出?

我尝试删除所有速度标签,但如果您有足够的 trkpts,问题仍然存在。它对额外的空白也很敏感,所以如果我在 trkpts 之间添加换行符,问题会出现在不同的点上或返回不同的属性值。

【问题讨论】:

  • 对我来说听起来像是 xml 解析器中的一个错误,您使用的是哪个 java 版本或哪个 xml 解析器?另外,xml没有定义属性的顺序,最好把attributes.getValue(0)换成attributes.getValue("lat")
  • 正如我所说,我正在使用 JRE 的内置 sax 解析,并且我尝试过 Sun6、OpenJDK6 和 OpenJDK7。而且我不在乎第一个属性是纬度还是经度,它的值仍然应该以'1'开头。
  • @Sami Korhonen,感谢您的链接。是的,这听起来确实像同样的问题,我只是有很多短属性而不是一些长属性。不幸的是,他的解决方案是使用 xml1.0,但我希望能够读取任何文件。
  • 解决方案是使用较新版本的 xerces(不是与您的 jre 捆绑的那个)

标签: java xml sax xml-1.1


【解决方案1】:

这个错误在 JDK XML 解析器中已经存在多年,Sun 和 Oracle 都没有表现出修复它的兴趣。我强烈建议优先使用 Apache Xerces XML 解析器。

【讨论】:

  • 我尝试搜索它,但没有找到任何东西。它是在官方错误跟踪器上报告的还是什么的?是否标记为 wontfix?
  • 对不起,我不知道。我想我至少在五年前就报告了它,但我自己在追踪器中找不到它。但有可能我从未报告过它,因为当你没有得到回应时你会放弃报告错误。无论如何,每隔几个月就会有人提出针对 Saxon 的错误报告,当他们切换到使用 Apache Xerces 时,该错误总是会消失。
  • 谢谢。我尝试了 Xerces 并且(到目前为止)不能让它以同样的方式失败。所以我认为对我来说最好的办法是尝试 使用 Xerces,如果不可用,则回退到内置的 sax 解析器(它适用于 xml 1.0)。
  • @MichaelKay 你能看看this。任何形式的帮助表示赞赏。
  • 我的建议很简单,不要使用 JDK 解析器,使用 Apache 的 Xerces。
猜你喜欢
  • 1970-01-01
  • 2011-09-14
  • 2017-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多