我们有一个处理 XML 文件的系统,其中文件本身太大而无法放入内存。
作为处理的一部分,我们希望快速扫描以记录相关元素的偏移量,以便稍后我们可以立即查找这些元素并只解析我们想要的部分(因为文件的较小部分会适合内存,我们可以负担得起为该部分使用 DOM 或其他任何东西。)
显然我们可以从头开始编写我们自己的 XML 解析器,但在制作另一个 XML 解析器之前,我想看看是否还有其他可用的选项。
以下是我们已经知道的事情的列表。
使用 StAX 应该行得通,但行不通。这是一个演示。我做了一个 XML 示例,其中有超过一个字节的字符,以证明一旦您开始传递这些字符,返回的字节偏移量就不正确。请注意,尽管 API 中的方法称为 getCharacterOffset(),但文档说如果您传入字节流,它会返回字节偏移量 - 这正是这段代码所做的。
@Test
public void testByteOffsetsFromStreamParser() throws Exception {
// byte counts are size required for UTF-8, I checked using Ishida's tool.
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<root>\n"
" <leaf>\u305A\u308C\u306A\u3044\u3067\u307B\u3057\u3044</leaf>\n" +
" <leaf>\u305A\u308C\u306A\u3044\u3067\u307B\u3057\u3044</leaf>\n" +
" <leaf>\u305A\u308C\u306A\u3044\u3067\u307B\u3057\u3044</leaf>\n" +
"</root>\n";
byte[] xmlBytes = xml.getBytes("UTF-8");
assertThat(xmlBytes.length, is(equalTo(171))); // = 171 from above
String implToTest = "com.sun.xml.internal.stream.XMLInputFactoryImpl";
//String implToTest = "com.ctc.wstx.stax.WstxInputFactory";
XMLInputFactory factory =
Class.forName(implToTest).asSubclass(XMLInputFactory.class).newInstance();
factory.setProperty("javax.xml.stream.isCoalescing", false);
factory.setProperty("javax.xml.stream.supportDTD", false);
XMLEventReader reader = factory.createXMLEventReader(
new ByteArrayInputStream(xmlBytes));
try {
XMLEvent event;
event = reader.nextTag(); // <root>
checkByteOffset(event, 39);
event = reader.nextTag(); // <leaf>
checkByteOffset(event, 47);
event = reader.nextEvent(); // (text)
checkByteOffset(event, 53);
event = reader.nextTag(); // </leaf>
checkByteOffset(event, 77);
event = reader.nextTag(); // <leaf>
checkByteOffset(event, 86);
event = reader.nextEvent(); // (text)
checkByteOffset(event, 92);
event = reader.nextTag(); // </leaf>
checkByteOffset(event, 116);
event = reader.nextTag(); // <leaf>
checkByteOffset(event, 125);
event = reader.nextEvent(); // (text)
checkByteOffset(event, 131);
event = reader.nextTag(); // </leaf>
checkByteOffset(event, 155);
event = reader.nextTag(); // </root>
checkByteOffset(event, 163);
} finally {
reader.close(); // no auto-close :(
}
}
private void checkByteOffset(XMLEvent event, int expectedOffset) {
System.out.println("Expected Offset: " + expectedOffset +
" - Actual Offset: " + event.getLocation().getCharacterOffset());
}
您在 Java 7 中默认获得的工厂结果:
Expected Offset: 39 - Actual Offset: 45
Expected Offset: 47 - Actual Offset: 53
Expected Offset: 53 - Actual Offset: 63
Expected Offset: 77 - Actual Offset: 68
Expected Offset: 86 - Actual Offset: 76
Expected Offset: 92 - Actual Offset: 86
Expected Offset: 116 - Actual Offset: 91
Expected Offset: 125 - Actual Offset: 99
Expected Offset: 131 - Actual Offset: 109
Expected Offset: 155 - Actual Offset: 114
Expected Offset: 163 - Actual Offset: 122
Woodstox 的结果,我们根据其他一些 stackoverflow 帖子建议进行了尝试。请注意,虽然它一开始是正确的,但在几行之后,它甚至比默认解析器更不正确:
Expected Offset: 39 - Actual Offset: 39
Expected Offset: 47 - Actual Offset: 47
Expected Offset: 53 - Actual Offset: 53
Expected Offset: 77 - Actual Offset: 61
Expected Offset: 86 - Actual Offset: 70
Expected Offset: 92 - Actual Offset: 76
Expected Offset: 116 - Actual Offset: 84
Expected Offset: 125 - Actual Offset: 93
Expected Offset: 131 - Actual Offset: 99
Expected Offset: 155 - Actual Offset: 107
Expected Offset: 163 - Actual Offset: 115
我们知道一个名为 VTD-XML 的库几乎完全符合我们的要求,但它有两个问题。第一个问题是它将整个文件读入内存,而文件本身放不下。第二个问题是许可证是 GPL,与我们的其他产品不兼容。
最佳答案
前段时间I created this approach为了娱乐。也许它会对你有所帮助。它主要执行以下操作。
关于java - 是否有一个好的 XML 解析器可以对 XML 文件进行光扫描以获取元素的字节偏移量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21010003/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当