我在this discussion中看到了几个很好的命令行XML操作工具,我正在探索通过脚本而不是编译程序从XML文件中提取数据的新方法。我目前正在尝试xmlstarlet,但我不限于使用此工具。
我有一个包含数万个元素的XML数据文件。我想基于搜索项列表提取这些元素的子集,然后管道或以其他方式将这些元素路由到某些下游脚本和转换。搜索词是简单的字符串 - 不需要正则表达式。如果我在常规文本文件中使用grep执行此操作,我可能会做一些简单的事情:
grep -Ff StringsToSearchFor.txt MassiveFile.txt | [chain of additional commands]
我一直在浏览像xmlstarlet这样的工具的文档,我可以实现这一点,而我能提出的最接近的事情就是这个使用临时文件的丑陋尝试。 (注意,我使用的是Windows):
REM Create tempOutput.xml, with an open root node
REM %1 is the file containing the list of strings
REM %2 is the target XML file
for /F %%A in (%1) do (
REM Search for a single matching node, and append the output to tempOutput.xml
xml sel -I -t -c "path/to/search[targetElement='%%A']" %2 >> tempOutput.xml
)
REM Close root node to tempOutput.xml
REM After this stage, pass tempOutput.xml as the input to downstream XML transforms and tools
毋庸置疑,这真的很难看。
我想有一种可能性就是修改for循环,将-c
XPath查询的巨大列表一次性传递给xmlstarlet,但这似乎也不必要地混乱,我认为我仍然会卡住使用tempOutput.xml文件。
有更优雅的方法吗?或者临时文件真的是我最好的方法吗?
答案 0 :(得分:1)
您可以编写一个XSLT样式表,将目标XML作为源文档,并使用document()
读取包含字符串列表的文件。 (如果您正在使用XSLT 2.0,则此文档不必是XML格式。)然后它可以解析字符串列表,并在目标XML文档中查找任何字符串的XPath匹配项:
<xsl:for-each select="$strings-to-match">
<xsl:for-each select="/path/to/search[targetElement = current()]">
<!-- whatever format you need to output these in... -->
<xsl:value-of select="." />
</xsl:for-each>
</xsl:for-each>
这将输出匹配元素的字符串值(连接的后代文本节点)。您可以根据下游程序的需要输出您想要的任何内容。
答案 1 :(得分:0)
使用我的Xidel,您可以这样写:
xidel --extract-exclude=search-terms StringsToSearchFor.txt -e '$search-terms := tokenize($raw, $line-ending)[. != ""]' MassiveFile.txt -e 'path/to/search[targetElement = $search-terms]'
但是对于一个大文件来说它可能有点慢(它曾经很快,即使使用流式xml,但是在实现完整的XQuery时我把所有优化都抛弃了;这已经很复杂了)。
答案 2 :(得分:0)
不仅如此,尤其是如果您反复分析该文件,请考虑尝试使用某些XML数据库。他们中的大多数都支持字符串搜索索引,这将大大加快搜索速度。您甚至可能对在XQuery中执行进一步分析感到非常满意。
执行搜索的XPath(XQuery子集)表达式将是
/path/to/search[targetElement = ('list', 'of', 'strings', 'to', 'search', 'for')]
某些实现支持XQuery Full Text,甚至可以增强文本搜索(尤其是使用高效索引):
/path/to/search[targetElement contains text { 'list', 'of', 'strings' }]
阅读这个单词列表很简单,但取决于它的存储方式以及您正在使用的实现。
BaseX是其中一个数据库(和开源软件,免责声明:我有点属于他们)。 galax还支持XQuery Full Text,其他着名的XML数据库和XQuery处理器是eXist DB,Saxon,Sedna和Marklogic。所有这些都有一些命令行工具可以将结果打印到STDOUT,因此您可以将其输入到剩余的处理链中。
如果任何子元素包含该字符串,则所有查询(包括您的查询)都将返回所有父元素。您可能希望使用targetElement/text()
来限制包含您正在寻找的针的那些元素。