Xmlstarlet / Sh - 将节点的内容复制到新节点/连接现有节点

Xmlstarlet / Sh - Copy content of a node into a new node / concat existing

我有以下 xml(例如)

<?xml version="1.0"?>
<gameList>
    <game>
        <path>./sunsetbl.zip</path>
        <name>sunsetbl</name>
        <playcount>8</playcount>
        <lastplayed>20180924T214132</lastplayed>
    </game>
    <game>
        <path>./ssriders.zip</path>
        <name>Sunset Riders (4 Players ver EAC)</name>
        <playcount>4</playcount>
        <lastplayed>20181030T013801</lastplayed>
    </game>
    <game>
        <path>./kof97.zip</path>
        <name>The King of Fighters '97 (NGM-2320)</name>
        <playcount>2</playcount>
        <lastplayed>20181030T035949</lastplayed>
    </game>
    <game>
        <path>./dino.zip</path>
        <name>Cadillacs and Dinosaurs (World 930201)</name>
        <favorite>true</favorite>
        <playcount>26</playcount>
        <lastplayed>20181030T043441</lastplayed>
    </game>
    <game>
        <path>./kof98n.zip</path>
        <name>kof98n</name>
        <playcount>1</playcount>
        <lastplayed>20181031T001024</lastplayed>
    </game>
</gameList>

好吧,我正在尝试编写一个 sh 脚本并在其上使用 xmlstarlet。对于每个游戏节点,我想复制路径节点并将其插入到一个名为描述的新节点中,如果描述已经存在,则将其连接到那里的现有文本。

我真的很菜鸟,这是我到现在为止能做的。

#!/bin/bash

set -e
shopt -s nullglob

for file in *.xml
do
  FILENAME=`xmlstarlet sel -t -m "/gameList/game" -v path $file`;
  echo "Appending $FILENAME into description on $file";
  xmlstarlet ed -L -s "/gameList/game" -t elem -n description -v "$FILENAME" $file;
done

当然,结果很糟糕,所有路径值都在一行中并复制到每个游戏节点,这就是它显示的结果

<?xml version="1.0"?>
<gameList>
  <game>
    <path>./sunsetbl.zip</path>
    <name>sunsetbl</name>
    <playcount>8</playcount>
    <lastplayed>20180924T214132</lastplayed>
    <description>./sunsetbl.zip./ssriders.zip./kof97.zip./dino.zip./kof98n.zip</description>
  </game>
  <game>
    <path>./ssriders.zip</path>
    <name>Sunset Riders (4 Players ver EAC)</name>
    <playcount>4</playcount>
    <lastplayed>20181030T013801</lastplayed>
    <description>./sunsetbl.zip./ssriders.zip./kof97.zip./dino.zip./kof98n.zip</description>
  </game>
  <game>
    <path>./kof97.zip</path>
    <name>The King of Fighters '97 (NGM-2320)</name>
    <playcount>2</playcount>
    <lastplayed>20181030T035949</lastplayed>
    <description>./sunsetbl.zip./ssriders.zip./kof97.zip./dino.zip./kof98n.zip</description>
  </game>
  <game>
    <path>./dino.zip</path>
    <name>Cadillacs and Dinosaurs (World 930201)</name>
    <favorite>true</favorite>
    <playcount>26</playcount>
    <lastplayed>20181030T043441</lastplayed>
    <description>./sunsetbl.zip./ssriders.zip./kof97.zip./dino.zip./kof98n.zip</description>
  </game>
  <game>
    <path>./kof98n.zip</path>
    <name>kof98n</name>
    <playcount>1</playcount>
    <lastplayed>20181031T001024</lastplayed>
    <description>./sunsetbl.zip./ssriders.zip./kof97.zip./dino.zip./kof98n.zip</description>
  </game>
</gameList>

我很乐意对此提供任何帮助。

如果可以使用单独的 XSLT 文件,解决方案如下。
使用此 XSLT 文件(此处命名为 trans.xslt):

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />

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

    <!-- Add 'path' value to existing 'description' element -->
    <xsl:template match="description">    
      <xsl:copy>
        <xsl:value-of select="concat(.,../path)" />
      </xsl:copy>
    </xsl:template>

    <!-- Create new 'description' element -->
    <xsl:template match="game[not(description)]">  
      <xsl:copy>
        <xsl:copy-of select="node()|@*" />
        <description>
            <xsl:value-of select="path" />
        </description>
      </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

并用这个脚本调用它:

#!/bin/bash
set -e
shopt -s nullglob

for file in *.xml
do
  xmlstarlet tr trans.xslt "$file" > "$file.new.xml"
done

这将创建扩展名为 filename.new.xml 的新文件。