如何将文本节提取到基于ID命名的单独文件中?

时间:2019-05-18 19:12:39

标签: xml shell loops svg sed

给出一个包含一系列重复文本部分的文本文件,我应该如何提取这些部分并将其存储在名称来源于每个部分ID的单独文本文件中?

  • 所有部分均以<?xml开头,并以</svg>结尾。
  • 所有部分都有一个id标记,应作为其名称的基础。

我不确定要在for loop中将两个sed REGEX组合在一起才能实现这一目标。


Original.svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="France" width="1500" height="1000" viewBox="0 0 3 2">
<rect width="3" height="2" fill="#009246"/>
<rect width="2" height="2" x="1" fill="#fff"/>
<rect width="1" height="2" x="2" fill="#ce2b37"/>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Italy" width="900" height="600">
<rect width="900" height="600" fill="#ED2939"/>
<rect width="600" height="600" fill="#fff"/>
<rect width="300" height="600" fill="#002395"/>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Ireland" width="1200" height="600">
<rect fill="#169b62" width="1200" height="600" />
<rect fill="#fff" x="400" width="800" height="600" />
<rect fill="#ff883e" x="800" width="400" height="600" />
</svg>

结果:

France.svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="France" width="1500" height="1000" viewBox="0 0 3 2">
<rect width="3" height="2" fill="#009246"/>
<rect width="2" height="2" x="1" fill="#fff"/>
<rect width="1" height="2" x="2" fill="#ce2b37"/>
</svg>

Italy.svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Italy" width="900" height="600">
<rect width="900" height="600" fill="#ED2939"/>
<rect width="600" height="600" fill="#fff"/>
<rect width="300" height="600" fill="#002395"/>
</svg>

Ireland.svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Ireland" width="1200" height="600">
<rect fill="#169b62" width="1200" height="600" />
<rect fill="#fff" x="400" width="800" height="600" />
<rect fill="#ff883e" x="800" width="400" height="600" />
</svg>

4 个答案:

答案 0 :(得分:1)

使用bash和xmlstarlet:

#!/bin/bash

while read -r line; do

  # fill variable with all lines and append newline to every line
  svg="$svg$line"$'\n'

  # last line?
  if [[ $line =~ \</svg\> ]]; then

    # extract attribute from xml
    svgfile=$(xmlstarlet select -N x='http://www.w3.org/2000/svg' --template --value-of '//x:svg/@id' <<< "$svg")

    # remove trailing newline and output xml to new file
    echo -e "${svg:0:-1}" > "${svgfile}.svg"

    unset svg
  fi
done < Original.svg

答案 1 :(得分:1)

使用用于多字符RS的GNU awk将每个SVG部分的文件分成有效的XML,进行协同处理以使我们将记录打印到xmlstarlet并读取输出,将第二个arg传递给close()以使我们关闭到xmlstarlet的管道,以便它处理输入,而xmlstarlet实际读取XML:

$ cat ../tst.awk
BEGIN {
    RS  = "</svg>[[:space:]]*"
    ORS = ""
    xmlParser = "xmlstarlet select -N x=\047http://www.w3.org/2000/svg\047 --template --value-of \047//x:svg/@id\047"
}
RT != "" {
    $0 = $0 RT

    print |& xmlParser
    close(xmlParser,"to")

    if ( (xmlParser |& getline id) > 0 ) {
        print > (id ".svg")
    }
    close(xmlParser)
}

例如,其中file包含问题的输入文本:

$ ls
file  tst.awk

$ awk -f tst.awk file

$ ls
file  tst.awk  France.svg  Ireland.svg  Italy.svg

$ tail -n +1 *.svg
==> France.svg <==
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="France" width="1500" height="1000" viewBox="0 0 3 2">
<rect width="3" height="2" fill="#009246"/>
<rect width="2" height="2" x="1" fill="#fff"/>
<rect width="1" height="2" x="2" fill="#ce2b37"/>
</svg>

==> Ireland.svg <==
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Ireland" width="1200" height="600">
<rect fill="#169b62" width="1200" height="600" />
<rect fill="#fff" x="400" width="800" height="600" />
<rect fill="#ff883e" x="800" width="400" height="600" />
</svg>

==> Italy.svg <==
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Italy" width="900" height="600">
<rect width="900" height="600" fill="#ED2939"/>
<rect width="600" height="600" fill="#fff"/>
<rect width="300" height="600" fill="#002395"/>
</svg>

如果</svg>位于注释或字符串中,并且可能还有其他您似乎没有的上下文,则失败。 idk如果XML部分中没有id,您要怎么做,所以如果发生这种情况,我只是不打印XML。

答案 2 :(得分:-1)

这是一种易碎但可移植的awk解决方案。

awk '
            {a[i++]=$0}
  /^<svg/   {for(f=1; f<=NF; f++) if($f~/^id=/) split($f, id, /["=]+/)}
  /^<\/svg/ {for(n=0; n<i; n++) print a[n] > (id[2] ".svg"); i=0}
' Original.svg
  1. 将按增量索引的数组中的每一行放入
  2. 在以<svg开头的行上,使用一个或多个等号或双引号将第三个字段分成数组id
  3. 在以</svg开头的行上,遍历数组,将每个元素(行)打印到文件中,方法是将拆分后的id[2]的第二个结果与文件扩展名“ .svg”连接在一起。

如果您有帮助,请考虑投票并选择此答案。我会回答任何问题。

答案 3 :(得分:-1)

这是一个简化的awk脚本,用于查询您的请求。 假设文件结构一致,为6行。

script.awk

{++line; lines = lines"\n"$0;}
NR%6 == 2 {id = substr($3, 5, length($3)-5)".svg"; next;}
NR%6 == 0 {
        print lines > id;
        line = 0; lines = "";
}

运行命令

awk -f script.awk Original.svg

如果您需要注释中的解释要求。