首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >缩进带有awk和xmllint的类XML文件

缩进带有awk和xmllint的类XML文件
EN

Stack Overflow用户
提问于 2015-01-21 15:38:06
回答 2查看 1.4K关注 0票数 0

我有一个“类似XML”的文件,其中包含大量的配置数据。我说" XML - like“,因为它真的像3个XML文件连接在一起,用”]>分隔。“

例如。

代码语言:javascript
复制
<?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,但是我得到了一个无法通过的错误。我把脚本和输出放在下面。

代码语言:javascript
复制
$ 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对这些文件进行操作,那么它就能工作了。

例如。

代码语言:javascript
复制
awk 'BEGIN {RS = "]]>]]>"} {print $0 > "Section_" NR ".txt" }' SmallTest.xml

这导致了三个文件Section_1.txt、Section_2.txt和Section_3.txt。Section_2.txt的内容如下:

代码语言:javascript
复制
$ cat Section_2.txt
<?xml version="1.0" encoding="UTF-8"?>
<data><lemur><type>"Ring-tailed"</type></lemur></data>

我可以用xmllint格式化该文件:

代码语言:javascript
复制
$ cat Section_2.txt | xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<data>
  <lemur>
    <type>"Ring-tailed"</type>
  </lemur>
</data>

所以,我不明白为什么我不能在awk脚本中首先将它输送到xmllint。

我很感激你能提供的任何帮助。

-Jon

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-21 16:07:49

简单地说,你的问题是awk一直在使用相同的管道。管道是在打开时使用的完全相同的字符串(这意味着不能同时运行两次完全相同的命令)下记住的,记录将一个接一个地写入其中,因此只有一个xmllint进程将整个文件作为输入。

您可以通过在每次记录之后关闭管道来修复此问题:

代码语言:javascript
复制
$ awk '
BEGIN {
    RS = "]]>]]>"
    xmlFormatCommand = "xmllint --format -"
} 

{
    print $0 | xmlFormatCommand 
    close(xmlFormatCommand)      # <-- HERE
}
' SmallTest.xml

在这里,close接受用于记住管道的标识符(命令)作为参数。我知道,与其他编程语言相比,这看起来很奇怪。

由于您在问题的末尾将有一个空记录,顺便说一句,您可能需要在其中添加一个条件,以排除这些空记录。例如,

代码语言:javascript
复制
$ awk '
BEGIN {
    RS = "]]>]]>"
    xmlFormatCommand = "xmllint --format -"
} 

! /^\s*$/ {  # <-- HERE
    print $0 | xmlFormatCommand 
    close(xmlFormatCommand)
}
' SmallTest.xml

其中,/^\s*$/匹配在开头和结尾之间只有空格的记录,而!则反转该匹配。

票数 1
EN

Stack Overflow用户

发布于 2015-01-21 16:20:31

这是由于print命令的输出一直指向xmllint的同一个实例。

解决这一问题的最简单方法是使用xmllint创建输出文件:

代码语言:javascript
复制
awk '
    BEGIN {
    RS = "]]>]]>"
} 
{
    print $0 | "xmllint --format --output sample_"NR".xml -"
}
' SmallTest.xml

如果这样做,您还会有一个错误,因为xmllint将在最后一行之后调用一次,而不留下任何输入-因此您可以只删除源xml中的最后一个分隔符,或者检查$0在awk脚本中是否有值。

若要将所有输出输出到stdout,请执行:

代码语言:javascript
复制
awk '
BEGIN {
RS = "]]>]]>"
} 
{
print $0 | "xmllint --format -"
close("xmllint --format -")}
' SmallTest.xml

请参阅node/Close-Files-And-Pipes.html

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28071089

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档