用于提取和验证 xml 个文件的 awk 管道
awk pipeline to extract and validate xml files
如何在管道中使用 awk 和 xmllint 提取和验证 xml 文件。
只提取文件的awk程序:
提取物xml
#!/usr/bin/awk -f
/<?xml version/{ getline doctype; getline datadoc;
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
fn=a[1]".xml"; print [=11=] ORS doctype ORS datadoc > fn; print a[1]".xml" ; next;
}}{ print > fn }
输入串联 xml 文件:
refcase.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa1234aa-20170101.XML">
<document-metatdata lang="EN" country="INTL">
<document-reference/>
</document-metatdata>
</data-document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa2345bb-20170202.XML">
<document-metatdata lang="EN" country="LOCAL">
<document-reference/>
</document-metatdata>
</data-document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa3456cc-20170303.XML">
<document-metatdata lang="EN" country="NA">
<document-reference/>
</document-metatdata>
</data-document>
验证命令:
xmllint --debug --dtdvalid refcase.dtd aa1234bb.xml
XML xmllint 用于验证 xml 文件的 dtd 文件:
refcase.dtd
<?xml encoding="UTF-8"?>
<!ELEMENT data-document (document-metatdata)>
<!ATTLIST data-document
xmlns CDATA #FIXED ''
date-published CDATA #REQUIRED
dtd-version CDATA #REQUIRED
file NMTOKEN #REQUIRED
<!ELEMENT document-metatdata (document-reference)>
<!ATTLIST document-metatdata
xmlns CDATA #FIXED ''
country NMTOKEN #REQUIRED
lang NMTOKEN #REQUIRED>
<!ELEMENT document-reference EMPTY>
<!ATTLIST document-reference
xmlns CDATA #FIXED ''>
当我将此代码添加到 awk 程序时:
{ print > fn } system("xmllint --debug --dtdvalid refcase.dtd " fn " > " a[1]".xml.rpt")
- awk 提取仍然可以正常工作,.xml 文件和以前一样创建。
- awk 输出现在传递给 xmllint 命令以进行 xml 验证,看起来 xmllint 命令的输入有问题。
提取文件并将输出发送到 xmllint 命令的 Awk 程序:
#!/usr/bin/awk -f
/<?xml version/{ getline doctype; getline datadoc;
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
fn=a[1]".xml"; print [=16=] ORS doctype ORS datadoc > fn; print a[1]".xml" ; next;
}}{ print > fn } system("xmllint --debug --dtdvalid refcase.dtd " fn " > " a[1]".xml.rpt")
在 awk 中调用时 xmllint 命令的问题输出:
aa1234aa.xml
aa1234aa.xml:5: parser error : Premature end of data in tag document-metatdata line 4
aa1234aa.xml:5: parser error : Premature end of data in tag data-document line 3
<document-metatdata lang="EN" country="INTL">
aa1234aa.xml:6: parser error : Premature end of data in tag document-metatdata line 4
aa1234aa.xml:6: parser error : Premature end of data in tag data-document line 3
<document-reference/>
aa1234aa.xml:7: parser error : Premature end of data in tag data-document line 3
在shell中执行命令时不会出现解析器错误,只有在awk程序中执行时才会出现错误。这对我来说表明提取的 xml 文件没问题。
这是对数千个串联的 txt 文件的提取过程,每个文件包含数千个 xml 文件。我需要跟踪和审核所有步骤并验证输出。
提取的 xml 个文件的预期输出:
aa1234aa.XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa1234aa-20170101.XML">
<document-metatdata lang="EN" country="INTL">
<document-reference/>
</document-metatdata>
</data-document>
aa2345bb.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa2345bb-20170202.XML">
<document-metatdata lang="EN" country="LOCAL">
<document-reference/>
</document-metatdata>
</data-document>
aa3456cc.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa3456cc-20170303.XML">
<document-metatdata lang="EN" country="NA">
<document-reference/>
</document-metatdata>
</data-document>
问题:
我希望 awk 将输出写入文件并将输出重定向到命令以进行进一步处理。
不确定 awk 是否是最好的提取工具,到目前为止它在测试数据上运行良好。我需要记录过程并验证输出。
感谢任何其他可靠且可扩展的方法吗?
您发布的命令是:
/<?xml version/{ getline doctype; getline datadoc;
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
fn=a[1]".xml"; print [=10=] ORS doctype ORS datadoc > fn; print a[1]".xml" ; next;
}}{ print > fn } system("xmllint --debug --dtdvalid refcase.dtd " fn " > " a[1]".xml.rpt")
第 1 步是修复它以使用合理的格式,以便我们可以看到控制流:
/<?xml version/{
getline doctype
getline datadoc;
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
fn=a[1]".xml"
print [=11=] ORS doctype ORS datadoc > fn
print a[1]".xml"
next
}
}
{ print > fn }
system("xmllint --debug --dtdvalid refcase.dtd " fn " > " a[1]".xml.rpt")
好的,现在我们一眼就可以看到 system() 调用是在一个条件块中而不是一个动作中,它没有关闭输出文件,它没有引用 xmllint文件名,它在多个地方硬编码 a[1]".xml" 所以让我们修复这些:
/<?xml version/{
getline doctype
getline datadoc
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
close(fn)
fn=a[1]".xml"
print [=12=] ORS doctype ORS datadoc > fn
print fn
next
}
}
{
print > fn
system("xmllint --debug --dtdvalid refcase.dtd 7" fn "7 > 7" fn ".rpt7")
}
现在让我们摆脱对 getline
的脆弱和不必要的调用:
/<?xml version/{
xmlversion = [=13=]
cnt = 3
}
cnt==2 {
doctype = [=13=]
}
cnt==1 {
datadoc = [=13=]
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
close(fn)
fn=a[1]".xml"
print xmlversion ORS doctype ORS datadoc > fn
print fn
next
}
}
cnt { cnt--; next }
{
print > fn
system("xmllint --debug --dtdvalid refcase.dtd 7" fn "7 > 7" fn ".rpt7")
}
现在我们可以看到您正在为输出的每一行调用 "xmllint",而不是为每个已完成的输出文件调用。将您的命令更改为:
/<?xml version/{
xmlversion = [=14=]
cnt = 3
}
cnt==2 {
doctype = [=14=]
}
cnt==1 {
if (match([=14=],/file="([^-]+)-[^"]+.XML"/,a)) {
lint(fn)
fn=a[1]".xml"
print xmlversion ORS doctype ORS [=14=] > fn
print fn
next
}
}
cnt { cnt--; next}
{ print > fn }
END { lint(fn) }
function lint(fn) {
if (fn != "") {
close(fn)
system("xmllint --debug --dtdvalid refcase.dtd 7" fn "7 > 7" fn ".rpt7")
fn = ""
}
}
最后,鉴于我现在对您的预期输出的了解,这就是我真正编写脚本的方式(还修复了 <?xml
和 [=19= 中未转义的正则表达式元字符 ?
] 在 .XML
中我之前没有发现):
/<\?xml version/ {
lint(fn)
fn = ""
}
match([=15=],/file="([^-]+)-[^"]+\.XML"/,a) {
fn = a[1]".xml"
[=15=] = prev2 ORS prev1 ORS [=15=]
print fn
}
{
if ( fn != "" ) {
print > fn
}
prev2 = prev1
prev1 = [=15=]
}
END { lint(fn) }
function lint(fn) {
if (fn != "") {
close(fn)
system("xmllint --debug --dtdvalid refcase.dtd 7" fn "7 > 7" fn ".rpt7")
}
}
如何在管道中使用 awk 和 xmllint 提取和验证 xml 文件。
只提取文件的awk程序:
提取物xml
#!/usr/bin/awk -f
/<?xml version/{ getline doctype; getline datadoc;
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
fn=a[1]".xml"; print [=11=] ORS doctype ORS datadoc > fn; print a[1]".xml" ; next;
}}{ print > fn }
输入串联 xml 文件:
refcase.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa1234aa-20170101.XML">
<document-metatdata lang="EN" country="INTL">
<document-reference/>
</document-metatdata>
</data-document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa2345bb-20170202.XML">
<document-metatdata lang="EN" country="LOCAL">
<document-reference/>
</document-metatdata>
</data-document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa3456cc-20170303.XML">
<document-metatdata lang="EN" country="NA">
<document-reference/>
</document-metatdata>
</data-document>
验证命令:
xmllint --debug --dtdvalid refcase.dtd aa1234bb.xml
XML xmllint 用于验证 xml 文件的 dtd 文件:
refcase.dtd
<?xml encoding="UTF-8"?>
<!ELEMENT data-document (document-metatdata)>
<!ATTLIST data-document
xmlns CDATA #FIXED ''
date-published CDATA #REQUIRED
dtd-version CDATA #REQUIRED
file NMTOKEN #REQUIRED
<!ELEMENT document-metatdata (document-reference)>
<!ATTLIST document-metatdata
xmlns CDATA #FIXED ''
country NMTOKEN #REQUIRED
lang NMTOKEN #REQUIRED>
<!ELEMENT document-reference EMPTY>
<!ATTLIST document-reference
xmlns CDATA #FIXED ''>
当我将此代码添加到 awk 程序时:
{ print > fn } system("xmllint --debug --dtdvalid refcase.dtd " fn " > " a[1]".xml.rpt")
- awk 提取仍然可以正常工作,.xml 文件和以前一样创建。
- awk 输出现在传递给 xmllint 命令以进行 xml 验证,看起来 xmllint 命令的输入有问题。
提取文件并将输出发送到 xmllint 命令的 Awk 程序:
#!/usr/bin/awk -f
/<?xml version/{ getline doctype; getline datadoc;
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
fn=a[1]".xml"; print [=16=] ORS doctype ORS datadoc > fn; print a[1]".xml" ; next;
}}{ print > fn } system("xmllint --debug --dtdvalid refcase.dtd " fn " > " a[1]".xml.rpt")
在 awk 中调用时 xmllint 命令的问题输出:
aa1234aa.xml
aa1234aa.xml:5: parser error : Premature end of data in tag document-metatdata line 4
aa1234aa.xml:5: parser error : Premature end of data in tag data-document line 3
<document-metatdata lang="EN" country="INTL">
aa1234aa.xml:6: parser error : Premature end of data in tag document-metatdata line 4
aa1234aa.xml:6: parser error : Premature end of data in tag data-document line 3
<document-reference/>
aa1234aa.xml:7: parser error : Premature end of data in tag data-document line 3
在shell中执行命令时不会出现解析器错误,只有在awk程序中执行时才会出现错误。这对我来说表明提取的 xml 文件没问题。
这是对数千个串联的 txt 文件的提取过程,每个文件包含数千个 xml 文件。我需要跟踪和审核所有步骤并验证输出。
提取的 xml 个文件的预期输出:
aa1234aa.XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa1234aa-20170101.XML">
<document-metatdata lang="EN" country="INTL">
<document-reference/>
</document-metatdata>
</data-document>
aa2345bb.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa2345bb-20170202.XML">
<document-metatdata lang="EN" country="LOCAL">
<document-reference/>
</document-metatdata>
</data-document>
aa3456cc.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data-document SYSTEM "refcase.dtd" [ ]>
<data-document lang="EN" dtd-version="v1 2017-01-01" file="aa3456cc-20170303.XML">
<document-metatdata lang="EN" country="NA">
<document-reference/>
</document-metatdata>
</data-document>
问题:
我希望 awk 将输出写入文件并将输出重定向到命令以进行进一步处理。
不确定 awk 是否是最好的提取工具,到目前为止它在测试数据上运行良好。我需要记录过程并验证输出。
感谢任何其他可靠且可扩展的方法吗?
您发布的命令是:
/<?xml version/{ getline doctype; getline datadoc;
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
fn=a[1]".xml"; print [=10=] ORS doctype ORS datadoc > fn; print a[1]".xml" ; next;
}}{ print > fn } system("xmllint --debug --dtdvalid refcase.dtd " fn " > " a[1]".xml.rpt")
第 1 步是修复它以使用合理的格式,以便我们可以看到控制流:
/<?xml version/{
getline doctype
getline datadoc;
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
fn=a[1]".xml"
print [=11=] ORS doctype ORS datadoc > fn
print a[1]".xml"
next
}
}
{ print > fn }
system("xmllint --debug --dtdvalid refcase.dtd " fn " > " a[1]".xml.rpt")
好的,现在我们一眼就可以看到 system() 调用是在一个条件块中而不是一个动作中,它没有关闭输出文件,它没有引用 xmllint文件名,它在多个地方硬编码 a[1]".xml" 所以让我们修复这些:
/<?xml version/{
getline doctype
getline datadoc
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
close(fn)
fn=a[1]".xml"
print [=12=] ORS doctype ORS datadoc > fn
print fn
next
}
}
{
print > fn
system("xmllint --debug --dtdvalid refcase.dtd 7" fn "7 > 7" fn ".rpt7")
}
现在让我们摆脱对 getline
的脆弱和不必要的调用:
/<?xml version/{
xmlversion = [=13=]
cnt = 3
}
cnt==2 {
doctype = [=13=]
}
cnt==1 {
datadoc = [=13=]
if (match(datadoc,/file="([^-]+)-[^"]+.XML"/,a)) {
close(fn)
fn=a[1]".xml"
print xmlversion ORS doctype ORS datadoc > fn
print fn
next
}
}
cnt { cnt--; next }
{
print > fn
system("xmllint --debug --dtdvalid refcase.dtd 7" fn "7 > 7" fn ".rpt7")
}
现在我们可以看到您正在为输出的每一行调用 "xmllint",而不是为每个已完成的输出文件调用。将您的命令更改为:
/<?xml version/{
xmlversion = [=14=]
cnt = 3
}
cnt==2 {
doctype = [=14=]
}
cnt==1 {
if (match([=14=],/file="([^-]+)-[^"]+.XML"/,a)) {
lint(fn)
fn=a[1]".xml"
print xmlversion ORS doctype ORS [=14=] > fn
print fn
next
}
}
cnt { cnt--; next}
{ print > fn }
END { lint(fn) }
function lint(fn) {
if (fn != "") {
close(fn)
system("xmllint --debug --dtdvalid refcase.dtd 7" fn "7 > 7" fn ".rpt7")
fn = ""
}
}
最后,鉴于我现在对您的预期输出的了解,这就是我真正编写脚本的方式(还修复了 <?xml
和 [=19= 中未转义的正则表达式元字符 ?
] 在 .XML
中我之前没有发现):
/<\?xml version/ {
lint(fn)
fn = ""
}
match([=15=],/file="([^-]+)-[^"]+\.XML"/,a) {
fn = a[1]".xml"
[=15=] = prev2 ORS prev1 ORS [=15=]
print fn
}
{
if ( fn != "" ) {
print > fn
}
prev2 = prev1
prev1 = [=15=]
}
END { lint(fn) }
function lint(fn) {
if (fn != "") {
close(fn)
system("xmllint --debug --dtdvalid refcase.dtd 7" fn "7 > 7" fn ".rpt7")
}
}