将XML标记值移动到其他标记

将XML标记值移动到其他标记,xml,bash,Xml,Bash,我正在尝试使用可以在bash中运行的命令创建一个简单的脚本,该命令允许我获取XML文件的值并重新排列它们。以此示例文件为例: <item1> <line>ASDF</line> <importantLine1>AAA</importantLine1> <importantLine2>BBB</importantLine2> <junkLine>CCC</junkL

我正在尝试使用可以在bash中运行的命令创建一个简单的脚本,该命令允许我获取XML文件的值并重新排列它们。以此示例文件为例:

<item1>
    <line>ASDF</line>
    <importantLine1>AAA</importantLine1>
    <importantLine2>BBB</importantLine2>
    <junkLine>CCC</junkLine>
    <importantLine3>DDD</importantLine3>
    <nest>
        <nestedLine>EEE</nestedLine>
    </nest>
</item1>
<item2>
    <line>ASDF</line>
    <importantLine1>AAA</importantLine1>
    <importantLine2>BBB</importantLine2>
    <junkLine>CCC</junkLine>
    <importantLine3>DDD</importantLine3>
    <nest>
        <nestedLine>EEE</nestedLine>
    </nest>
</item2>
<item3>
    <line>ASDF</line>
    <importantLine1>AAA</importantLine1>
    <importantLine2>BBB</importantLine2>
    <junkLine>CCC</junkLine>
    <importantLine3>DDD</importantLine3>
    <nest>
        <nestedLine>EEE</nestedLine>
    </nest>
</item3>

ASDF
AAA
BBB
CCC
DDD
EEE
ASDF
AAA
BBB
CCC
DDD
EEE
ASDF
AAA
BBB
CCC
DDD
EEE

我想让输出看起来像这样,将一些标记中的值移动到一个标记中:

<item1>
    <line>ASDF</line>
    <importantLine2>DDD "AAA" BBB [EEE]</importantLine2>
    <junkLine>CCC</junkLine>
</item1>
<item2>
    <line>ASDF</line>
    <importantLine2>DDD "AAA" BBB [EEE]</importantLine2>
    <junkLine>CCC</junkLine>
</item2>
<item3>
    <line>ASDF</line>
    <importantLine2>DDD "AAA" BBB [EEE]</importantLine2>
    <junkLine>CCC</junkLine>
</item3>

ASDF
DDD“AAA”BBB[EEE]
CCC
ASDF
DDD“AAA”BBB[EEE]
CCC
ASDF
DDD“AAA”BBB[EEE]
CCC
如果有什么不同的话,我想学习如何移动这些值,而不仅仅是一个让它发生的答案。“教人钓鱼…”

使用XSLT文件可以实现这一点。元素的顺序并不完全正确,但如果没有任何标准,这是最好的。如有必要,可使用
等命令对输出进行排序

您必须将所有
项???
元素放在一个根元素中,此解决方案才能工作

reorder.xslt

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="/">
    <xsl:apply-templates />
  </xsl:template>

  <xsl:template match="*[starts-with(local-name(),'item')]">
    <xsl:copy>
      <xsl:copy-of select="line" /> 
      <importantLine2>
      <xsl:for-each select="*[starts-with(local-name(),'importantLine')]">
        <xsl:value-of select="concat(text(),' ')"/>     
      </xsl:for-each>
      <xsl:for-each select="nest/nestedLine">
        <xsl:text>[</xsl:text><xsl:value-of select="concat(text(),' ')"/><xsl:text>]</xsl:text>
      </xsl:for-each>
      </importantLine2>
      <xsl:copy-of select="junkLine" /> 
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
输出为:

<item1>
    <line>ASDF</line>
    <importantLine2>AAA BBB DDD [EEE ]</importantLine2>
    <junkLine>CCC</junkLine>
</item1>
<item2>
    <line>ASDF</line>
    <importantLine2>AAA BBB DDD [EEE ]</importantLine2>
    <junkLine>CCC</junkLine>
</item2>
<item3>
    <line>ASDF</line>
    <importantLine2>AAA BBB DDD [EEE ]</importantLine2>
    <junkLine>CCC</junkLine>
</item3>

ASDF
AAA BBB DDD[EEE]
CCC
ASDF
AAA BBB DDD[EEE]
CCC
ASDF
AAA BBB DDD[EEE]
CCC

xmlstarlet
解决方案:

假设具有“根”(主)节点的有效XML文档:

  • ed
    -编辑模式
  • -O
    -省略XML声明
    ()
  • -u
    -更新操作;完整签名:
    -u或--update-v(--value)-x(--expr)
  • -d
    -删除操作;完整签名:
    -d或--delete

输出:

<root>
  <item1>
    <line>ASDF</line>
    <importantLine2>DDD AAA BBB [EEE]</importantLine2>
    <junkLine>CCC</junkLine>
  </item1>
  <item2>
    <line>ASDF</line>
    <importantLine2>DDD AAA BBB [EEE]</importantLine2>
    <junkLine>CCC</junkLine>
  </item2>
  <item3>
    <line>ASDF</line>
    <importantLine2>DDD AAA BBB [EEE]</importantLine2>
    <junkLine>CCC</junkLine>
  </item3>
</root>

ASDF
DDD AAA BBB[EEE]
CCC
ASDF
DDD AAA BBB[EEE]
CCC
ASDF
DDD AAA BBB[EEE]
CCC

为什么要使用bash?使用
xsltproc
(仅25k)和XSLT模板肯定会更容易。应该已经澄清了。我指的是可以在bash中运行的命令。很抱歉我将快速编辑它,我建议使用xmlint和xpath。其他常见的XML工具有
xmlstarlet
xmlto
。如果Bash只是指shell的内置工具,或者只指通常安装的核心工具,如Awk和
sed
,那么您将受到伤害。
xmlstarlet ed -O -u "//importantLine2" \
-x 'concat(parent::*/importantLine3, " ", parent::*/importantLine1, " ", . , 
   " [", parent::*//nestedLine, "]")' \
-d '//importantLine1 | //importantLine3 | //nest' xmlfile
<root>
  <item1>
    <line>ASDF</line>
    <importantLine2>DDD AAA BBB [EEE]</importantLine2>
    <junkLine>CCC</junkLine>
  </item1>
  <item2>
    <line>ASDF</line>
    <importantLine2>DDD AAA BBB [EEE]</importantLine2>
    <junkLine>CCC</junkLine>
  </item2>
  <item3>
    <line>ASDF</line>
    <importantLine2>DDD AAA BBB [EEE]</importantLine2>
    <junkLine>CCC</junkLine>
  </item3>
</root>