是否有一种简单的方法,可能是使用 XPath 查询(或可以在每个linux / osx机器中轻松找到的任何其他命令行工具)从大型XML文件中提取子集原始文件?
具体来说,我有一个格式为:
的大型xml文件<root>
<header>...<>
<item name="1">...<>
<item name="2">...<>
...
<item name="1000000">..<>
</root>
我希望输出一个较小的XML文件,其中包含头部的前k项(比如10个)。作为旁注,请考虑该文件可能已损坏。基本上我正在寻找一个类似于head
的命令,它使用SAX解析器解析XML文件(为了不占用内存并且对文件过早终止具有弹性)。
答案 0 :(得分:2)
我认为使用xsl:iterate
的流处理允许在XSLT 3.0中当前由Saxon 9.7 EE实现(显然它不是LINUX上容易使用的命令行工具,但是因为它确实解决了我认为它的问题值得一提的是:假设形式为test2015122701.xml
的形式不正确的XML
<root>
<header>...</header>
<item name="1">...</item>
<item name="2">...</item>
<item name="3">...</item>
<item name="4">...</item>
<item>
</root>
和带代码的XSLT 3.0样式表
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="items-to-copy" as="xs:integer" select="4"/>
<xsl:variable name="children-to-copy" as="xs:integer" select="$items-to-copy + 1"/>
<xsl:param name="input-uri" as="xs:string" select="'test2015122701.xml'"/>
<xsl:output indent="yes"/>
<xsl:template name="main" match="/">
<root>
<xsl:stream href="{$input-uri}">
<xsl:iterate select="root/*">
<xsl:copy-of select="."/>
<xsl:if test="position() eq $children-to-copy">
<xsl:break/>
</xsl:if>
</xsl:iterate>
</xsl:stream>
</root>
</xsl:template>
</xsl:stylesheet>
Saxon 9.7 EE,当使用java -jar saxon9ee.jar -it:main -xsl:sheet.xsl
运行时会产生以下输出:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<header>...</header>
<item name="1">...</item>
<item name="2">...</item>
<item name="3">...</item>
<item name="4">...</item>
</root>
如果我们使用-t
命令行选项运行以检查处理的一些细节,我们会看到:
Streaming file:/C:/Users/Martin%20Honnen/Documents/xslt/test2015122701.xml
URIResolver.resolve href="test2015122701.xml" base="file:/C:/Users/Martin%20Honnen/Documents/xslt/test2015122702.xsl"
Using parser com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser
Streaming test2015122701.xml : early exit
因此Saxon确实只处理文件的开头并在遇到第一个元素之后的格式不正确的标记之前退出。
答案 1 :(得分:0)
作为替代方案,这里有一个使用Perl和XML :: Twig的例子:
use strict;
use XML::Twig;
my $itemCount = 0;
my $breakCount = 4;
sub count_items {
my ($t, $item) = @_;
$itemCount++;
if ($itemCount == $breakCount) {
$t->finish_now();
}
}
my $input = 'input.xml';
my $result = 'output.xml';
my $twig = XML::Twig->new(
twig_handlers => { item => \&count_items},
pretty_print => 'indented'
);
$twig->parsefile($input);
$twig->print_to_file($result);
恐怕我不知道LINUX上支持Perl和XML :: Twig的程度如何,我已经在Windows上使用Perl 5.20.3使用XML :: Twig 3.49测试了上述内容。