如何在树中移动 xml 文件中的元素

How to move elements in an xml file within the tree

我有一个 xml 文件,格式如下:

<results>
 <sequence-name>name1</sequence-name>
 <repetitions>
  <window>
   <key1>1</key1>
  </window>
 </repetitions>
 <sequence-name>name2</sequence-name>
 <repetitions>
  <window>
   <key1>4</key1>
  </window>
  </repetitions>
</results>

我想移动元素 sequence-name 使其成为 window 中的第一个元素,因此输出应如下所示:

<results>    
 <repetitions>
  <window>
   <sequence-name>name1</sequence-name>
   <key1>1</key1>
  </window>
 </repetitions>    
 <repetitions>
  <window>
   <sequence-name>name2</sequence-name>
   <key1>4</key1>
  </window>
 </repetitions>
</results>

我尝试使用 grep 生成两个文件,一个只包含带有 <sequence-name> 的行,另一个包含所有其他行。但我不知道如何将包含 <sequence-name> 的行插入到我想要的位置。我猜有一个使用 sed/awk 的解决方案。我也很乐意使用 xmlstarlet.

这样的工具

如果您的文件始终格式正确并且在 xmlstarlet 中非常重要:

$ awk '/<sequence-name>/{s=[=10=];next} {print} /<window>/{print s}' file
<results>
 <repetitions>
  <window>
 <sequence-name>name1</sequence-name>
   <key1>1</key1>
  </window>
 </repetitions>
 <repetitions>
  <window>
 <sequence-name>name2</sequence-name>
   <key1>4</key1>
  </window>
  </repetitions>
</results>

如果您关心缩进:

$ awk '/<sequence-name>/{s=[=11=]; next} {print} /<window>/{indent=[=11=]; sub(/[^[:space:]].*/," ",indent); sub(/^[[:space:]]*/,indent,s); print s}' file
<results>
 <repetitions>
  <window>
   <sequence-name>name1</sequence-name>
   <key1>1</key1>
  </window>
 </repetitions>
 <repetitions>
  <window>
   <sequence-name>name2</sequence-name>
   <key1>4</key1>
  </window>
  </repetitions>
</results>

下面的样式表应该可以解决问题:

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

<xsl:template match="/ | node()">
  <xsl:copy>
    <xsl:apply-templates select="node()[not(self::sequence-name)]" />
  </xsl:copy>
</xsl:template>

<xsl:template match="window">
  <xsl:copy>
    <xsl:copy-of select="preceding::sequence-name[1]" />
    <xsl:apply-templates select="key1"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

您可以使用 xsltproc stylesheet dataxmlstarlet tr stylesheet data 应用它。

另一种方法,只使用 sed:

$ sed '/<sequence-name>/{s/^/  /; h; d;}; /<window>/G;' file
<results>
 <repetitions>
  <window>
   <sequence-name>name1</sequence-name>
   <key1>1</key1>
  </window>
 </repetitions>
 <repetitions>
  <window>
   <sequence-name>name2</sequence-name>
   <key1>4</key1>
  </window>
  </repetitions>
</results>