使用StAX保留XML布局(属性顺序,换行符)以进行小的更改(例如更改属性)

时间:2016-06-16 20:40:21

标签: java xml-parsing stax

我正在尝试使用StAX迭代器API替换SVG文件中某些属性的值。我使用XMLEventReader阅读原始文件,检查和修改元素,然后写入XMLEventWriter

我的原始文件具有以下结构:

<?xml version="1.0" encoding="UTF-8"?>
<!--
...
-->
<!DOCTYPE ...
...
]>
<svg ...

我得到的输出不一样:

<?xml version="1.0"?><!--
...
--><!DOCTYPE ...
...
]><svg ...

正如您所看到的,encoding已消失,评论和文档类型的换行符也已消失。

此外,生成的文件中所有标记的所有属性的顺序似乎是随机的。我已阅读another question并且我知道属性顺序无法保证,但这对我没有帮助。

这些SVG文件在Git下,所以我想尽可能保留它们的纯文本布局。

如何解决这些问题?使用我当前的任务,我可以将属性值替换为纯文本,而无需任何解析,但我希望有一个解决方案,允许我将标记嵌套和类似的东西考虑在内。

如果无法使用StAX,我完全接受不同的方法。我已经尝试过DOM方法了,情况更糟。也许有一些3D派对解析器...

2 个答案:

答案 0 :(得分:1)

VTD-XML(我是作者的一个开源项目)是java API,在导出XML树的层次结构时解析后保留底层字节......这意味着你可以替换任何部分原位字节,没有任何不必要的文件无关部分的摆弄..甚至直接覆盖字节......零开销

答案 1 :(得分:0)

在涉及更新属性的情况下,最佳选择不使用XMLEventWriter,而是在XML文件中查找标记的位置(字符偏移)并进行子字符串替换。你可以这样做:

  1. 使用XMLEventReader,遍历文件
  2. 当您遇到要更改属性的元素时,请使用XMLEvent#getLocation(),然后在其上调用getCharacterOffset(),这将返回原始文件中发出此事件的位置。< / LI>
  3. 通过跟踪先前元素和当前元素的偏移量,您可以从原始文件的内容中仅提取一个元素的子字符串。
  4. 更新子字符串,将其与之前和之后的文本连接,这将为您提供更新的XML作为字符串。由于提取的子字符串只包含一个元素,因此您可以放心地假设所有属性都是唯一的,因此您可以根据需要添加,删除和更新它们,而不必担心意外触摸其他元素。
  5. 将更新的内容以字符串形式写入文件。
  6. 下行:您必须手动解析属性,但在大多数情况下这是微不足道的。

    另外,我发现Characters个事件存在问题:在后续的<</消耗后会报告这些事件。例如,在<foo>bar</foo>中,bar字符将被报告为bar</

    这在StAX的其他实现中可能有所不同,我使用的是Java库中的默认实现。我假设这种行为可以解释为StAX解析器永远不会倒退,当它有足够的信息来检测字符结束事件时,它已经消耗了下一个元素的开头(打开或关闭标记)。

    至于我原来尝试使用XMLEventWriter

    • 可以通过显式构建新的StartDocument事件来添加缺少encoding的XML标头。
    • 可以手动添加缺少换行符,但我找不到任何标记来保留它们。它似乎与上面的问题有关:解析器报告这些元素的偏移以及换行符(有时它们是前置的,有时是附加的)。
    • 属性的随机顺序只能通过自定义解析器修复,如@ vtd-xml-author
    • 所述