[英]Indent XML-like file with awk and xmllint
我有一個“類似XML”的文件,其中包含許多配置數據。 我說“類似XML”是因為它實際上就像是3個XML文件串聯在一起,並以“]]>]]>”分隔
例如
<?xml version="1.0" encoding="UTF-8"?>
<hello><world>"Earth"</world></hello>]]>]]><?xml version="1.0" encoding="UTF-8"?>
<data><lemur><type>"Ring-tailed"</type></lemur></data>]]>]]><?xml version="1.0" encoding="UTF-8"?>
<data><lemur><type>"Mouse"</type></lemur></data>]]>]]>
我正在嘗試編寫一個腳本,該腳本將調用xmllint來縮進文件中的所有XML標記。 但是,xmllint(以及許多其他xml格式化程序)似乎要求文件中只有一個XML文檔。 例如,文件需要以“ <?xml version="1.0" encoding="UTF-8"?>
“開頭,並且僅包含一個根樹。
因此,我嘗試編寫一個awk腳本,該腳本會將數據解析為單獨的塊並將其傳遞給xmllint,但是出現一個我無法逾越的錯誤。 我將腳本和輸出放在下面。
$ awk '
BEGIN {
RS = "]]>]]>"
xmlFormatCommand = "xmllint --format -"
}
{
print $0 | xmlFormatCommand
}
' SmallTest.xml
-:3: parser error : XML declaration allowed only at the start of the document
<?xml version="1.0" encoding="UTF-8"?>
^
-:4: parser error : Extra content at the end of the document
<data><lemur><type>"Ring-tailed"</type></lemur></data>
^
如果我在兩個單獨的操作中執行此操作,則其中awk打印到三個臨時文件,而其中xmllint在這些文件上進行操作,那么它將起作用。
例如
awk 'BEGIN {RS = "]]>]]>"} {print $0 > "Section_" NR ".txt" }' SmallTest.xml
這將產生三個文件Section_1.txt,Section_2.txt和Section_3.txt。 Section_2.txt的內容是:
$ cat Section_2.txt
<?xml version="1.0" encoding="UTF-8"?>
<data><lemur><type>"Ring-tailed"</type></lemur></data>
我可以使用xmllint格式化該文件:
$ cat Section_2.txt | xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<data>
<lemur>
<type>"Ring-tailed"</type>
</lemur>
</data>
所以我不明白為什么我不能僅僅將它通過awk腳本通過管道傳遞給xmllint。
感謝您提供的任何幫助。
-喬恩
簡而言之,您的問題是awk繼續使用同一管道。 記住該管道是在打開該管道的完全相同的字符串下進行的(這意味着您無法同時運行完全相同的命令兩次),並且記錄是一個接一個地寫入其中的,因此只有一個xmllint
進程將整個文件作為輸入。
您可以通過在每條記錄后關閉管道來解決此問題:
$ awk '
BEGIN {
RS = "]]>]]>"
xmlFormatCommand = "xmllint --format -"
}
{
print $0 | xmlFormatCommand
close(xmlFormatCommand) # <-- HERE
}
' SmallTest.xml
這里, close
接受記住管道的標識符(命令)作為參數。 我知道,與其他編程語言相比,這看起來很奇怪。
順便說一句,由於問題的文件末尾會有一個空記錄,因此,您可能希望在其中放置一個排除此類空記錄的條件。 例如,
$ awk '
BEGIN {
RS = "]]>]]>"
xmlFormatCommand = "xmllint --format -"
}
! /^\s*$/ { # <-- HERE
print $0 | xmlFormatCommand
close(xmlFormatCommand)
}
' SmallTest.xml
/^\\s*$/
匹配在開頭和結尾之間只有空格的記錄,以及!
反轉匹配。
這是由於以下事實:print命令的輸出將繼續轉到xmllint的相同實例。
解決此問題的最簡單方法就是也使用xmllint創建輸出文件:
awk '
BEGIN {
RS = "]]>]]>"
}
{
print $0 | "xmllint --format --output sample_"NR".xml -"
}
' SmallTest.xml
如果這樣做,將剩下一個錯誤,因為xmllint將在最后一行之后被調用一次,而沒有任何輸入-因此,您可以刪除源xml中的最后一個定界符,或者檢查$ 0在awk中是否有值腳本。
要將所有內容輸出到stdout,請執行以下操作:
awk '
BEGIN {
RS = "]]>]]>"
}
{
print $0 | "xmllint --format -"
close("xmllint --format -")}
' SmallTest.xml
參見https://www.gnu.org/software/gawk/manual/html_node/Close-Files-And-Pipes.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.