解析XML文件并基于现有密钥添加新密钥

时间:2017-12-29 14:59:08

标签: xml bash methods xml-parsing xmlstarlet

我真的在寻找关于在bash中解决这个问题的最佳方法的一些建议。

我有一个包含1000个条目的XML文件,如下所示:

<?xml version="1.0"?>
<myList>
    <dataitem>
        <path>./5553 Subset 43d.zip</path>
        <name>5553 Subset 43d</name>
    </dataitem>
    <dataitem>
        <path>./Another file name here with spaces.zip</path>
        <name>Another file name here with spaces</name>
    </dataitem>
...

我想使用带有mp4扩展名的<dataitem>密钥数据为每个<name>添加一个额外的密钥,所以它看起来像这样:

<?xml version="1.0"?>
<myList>
    <dataitem>
        <path>./5553 Subset 43d.zip</path>
        <name>5553 Subset 43d</name>
        <video>5553 Subset 43d.mp4</video>
    </dataitem>
    <dataitem>
        <path>./Another file name here with spaces.zip</path>
        <name>Another file name here with spaces</name>
        <video>Another file name here with spaces.mp4</video>
    </dataitem>
...

2 个答案:

答案 0 :(得分:1)

使用 xmlstarlet 工具的正确方法:

xmlstarlet ed -s "//dataitem" -t elem -n video input.xml \
| xmlstarlet ed -u "//dataitem/video" -x "concat(./preceding-sibling::name/text(), '.mp4')"

输出应为:

<?xml version="1.0"?>
<myList>
  <dataitem>
    <path>./5553 Subset 43d.zip</path>
    <name>5553 Subset 43d</name>
    <video>5553 Subset 43d.mp4</video>
  </dataitem>
  <dataitem>
    <path>./Another file name here with spaces.zip</path>
    <name>Another file name here with spaces</name>
    <video>Another file name here with spaces.mp4</video>
  </dataitem>
...

答案 1 :(得分:1)

或者,考虑XSLT,这是一种用于转换XML的专用语言,使用bash调用xsltproc

XSLT (另存为.xsl文件,一个特殊的.xml文件)

a = [1,2,3]
b = [4,5,6]
c = a ++ [some_atom: b]

[1,2,3, some_atom:[4,5,6]] = c  # pattern matching passes

Bash (假设本地cd路径,使用已安装的xsltproc)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
    </xsl:template>

    <xsl:template match="dataitem">
     <xsl:copy>
       <xsl:copy-of select="*"/>
       <video><xsl:value-of select="concat(name, '.mp4')"/></video>
     </xsl:copy>
    </xsl:template>

</xsl:stylesheet>