根据标签数将单个 XML 文件拆分为 2 个文件
split a single XML file into 2 files based on tag count
我有一个 XML 文件,它由许多 XML 条记录组成,这些记录由如下标记限定:
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273127</PMID>
...
...
...
</PubmedArticle>
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273128</PMID>
...
...
...
</PubmedArticle>
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273129</PMID>
...
...
...
</PubmedArticle>
我可以使用
生成单个文件
awk '/<PubmedArticle/{f=1; out="mysmallfile_"(++c)".xml"} f{print > out} /<\/PubmedArticle>/{close(out); f=0}' mylargefile
见
如何生成由特定数量的记录组成的文件?例如,假设我有一个包含 1000 XML 条记录的大型 XML 文件,我想创建 2 x 500 XML 条记录文件?
我认为 awk 应该保存到一个文件,直到它满足定义的标签匹配数,然后再保存到另一个文件。
这部分
/<PubmedArticle/{f=1; out="mysmallfile_"(++c)".xml"}
可以修改为通过利用整数除法给出相同的 out
n
次,例如对于 n=3 它将是
/<PubmedArticle/{f=1; out="mysmallfile_"int(c++/3)".xml"}
这将为匹配 <PubmedArticle
的后续行提供
mysmallfile_0.xml
mysmallfile_0.xml
mysmallfile_0.xml
mysmallfile_1.xml
mysmallfile_1.xml
mysmallfile_1.xml
mysmallfile_2.xml
mysmallfile_2.xml
mysmallfile_2.xml
等等。请注意,我使用 c++
而不是 ++c
,因为稍后使用会首先重复 n-1
次,然后 n
次。
这部分
/<\/PubmedArticle>/{close(out); f=0}
可以使用除法余数进行如下调整
/<\/PubmedArticle>/&&c%3==0{close(out); f=0}
当 c
被 3
整除时,附加条件成立,这仅适用于给定 out
.
的最后一次使用
(在 GNU Awk 5.0.1 中测试)
你的问题和你引用的问题之间的区别在于,他们的输入中有块,他们不想出现在输出中,而你希望输入的每一行都出现在输出文件中,因此,虽然他们只需要打印开始和结束标记之间的内容,因此必须对两者进行测试,但您没有这个问题,只需要测试开始或结束标记以确定何时更改输出文件。
使用任何 awk:
$ awk -v maxRecs=2 '
/<PubmedArticle>/ && ((++recNr % maxRecs) == 1) {
close(out); out="mysmallfile_" (++fileNr) ".xml"
}
{ print > out }
' file
$ head mysmallfile*
==> mysmallfile_1.xml <==
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273127</PMID>
...
...
...
</PubmedArticle>
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
==> mysmallfile_2.xml <==
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273129</PMID>
...
...
...
</PubmedArticle>
或使用 GNU awk 用于 multi-char RS 和 RT:
$ awk -v maxRecs=2 -v RS='</PubmedArticle>\n' -v ORS= '
(NR % maxRecs) == 1 {
close(out); out="mysmallfile_" (++fileNr) ".xml"
}
RT { print [=12=] RT > out }
' file
$ head mysmallfile*
==> mysmallfile_1.xml <==
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273127</PMID>
...
...
...
</PubmedArticle>
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
==> mysmallfile_2.xml <==
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273129</PMID>
...
...
...
</PubmedArticle>
我正在调用 close()
关闭每个输出文件,因为我们要避免大多数 awk 可能出现的“打开文件过多”错误或 gawk 变慢。
以上假定您的目标是创建尽可能多的“maxRecs”长度的文件,然后将输入的剩余部分放入最后一个文件中,因此如果您有一个包含 800 条记录的输入文件,您我将得到一个包含 500 条记录的输出文件和另一个 300 条记录的输出文件,而不是两个 400 条记录的输出文件。
我有一个 XML 文件,它由许多 XML 条记录组成,这些记录由如下标记限定:
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273127</PMID>
...
...
...
</PubmedArticle>
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273128</PMID>
...
...
...
</PubmedArticle>
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273129</PMID>
...
...
...
</PubmedArticle>
我可以使用
生成单个文件awk '/<PubmedArticle/{f=1; out="mysmallfile_"(++c)".xml"} f{print > out} /<\/PubmedArticle>/{close(out); f=0}' mylargefile
见
如何生成由特定数量的记录组成的文件?例如,假设我有一个包含 1000 XML 条记录的大型 XML 文件,我想创建 2 x 500 XML 条记录文件?
我认为 awk 应该保存到一个文件,直到它满足定义的标签匹配数,然后再保存到另一个文件。
这部分
/<PubmedArticle/{f=1; out="mysmallfile_"(++c)".xml"}
可以修改为通过利用整数除法给出相同的 out
n
次,例如对于 n=3 它将是
/<PubmedArticle/{f=1; out="mysmallfile_"int(c++/3)".xml"}
这将为匹配 <PubmedArticle
mysmallfile_0.xml
mysmallfile_0.xml
mysmallfile_0.xml
mysmallfile_1.xml
mysmallfile_1.xml
mysmallfile_1.xml
mysmallfile_2.xml
mysmallfile_2.xml
mysmallfile_2.xml
等等。请注意,我使用 c++
而不是 ++c
,因为稍后使用会首先重复 n-1
次,然后 n
次。
这部分
/<\/PubmedArticle>/{close(out); f=0}
可以使用除法余数进行如下调整
/<\/PubmedArticle>/&&c%3==0{close(out); f=0}
当 c
被 3
整除时,附加条件成立,这仅适用于给定 out
.
(在 GNU Awk 5.0.1 中测试)
你的问题和你引用的问题之间的区别在于,他们的输入中有块,他们不想出现在输出中,而你希望输入的每一行都出现在输出文件中,因此,虽然他们只需要打印开始和结束标记之间的内容,因此必须对两者进行测试,但您没有这个问题,只需要测试开始或结束标记以确定何时更改输出文件。
使用任何 awk:
$ awk -v maxRecs=2 '
/<PubmedArticle>/ && ((++recNr % maxRecs) == 1) {
close(out); out="mysmallfile_" (++fileNr) ".xml"
}
{ print > out }
' file
$ head mysmallfile*
==> mysmallfile_1.xml <==
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273127</PMID>
...
...
...
</PubmedArticle>
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
==> mysmallfile_2.xml <==
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273129</PMID>
...
...
...
</PubmedArticle>
或使用 GNU awk 用于 multi-char RS 和 RT:
$ awk -v maxRecs=2 -v RS='</PubmedArticle>\n' -v ORS= '
(NR % maxRecs) == 1 {
close(out); out="mysmallfile_" (++fileNr) ".xml"
}
RT { print [=12=] RT > out }
' file
$ head mysmallfile*
==> mysmallfile_1.xml <==
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273127</PMID>
...
...
...
</PubmedArticle>
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
==> mysmallfile_2.xml <==
<PubmedArticle>
<MedlineCitation Status="MEDLINE" Owner="NLM">
<PMID Version="1">24273129</PMID>
...
...
...
</PubmedArticle>
我正在调用 close()
关闭每个输出文件,因为我们要避免大多数 awk 可能出现的“打开文件过多”错误或 gawk 变慢。
以上假定您的目标是创建尽可能多的“maxRecs”长度的文件,然后将输入的剩余部分放入最后一个文件中,因此如果您有一个包含 800 条记录的输入文件,您我将得到一个包含 500 条记录的输出文件和另一个 300 条记录的输出文件,而不是两个 400 条记录的输出文件。