簡體   English   中英

使用awk和xmllint縮進類似XML的文件

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM