XMLStarlet:使用xpath将元素移动到另一个元素之前

时间:2017-03-22 17:57:03

标签: xml xpath xmlstarlet

假设:

<x>
  <a />
  <d />
  <b />
  <c />
  <e />
  <f />
</x>

我想使用xmlstarlet将<d />移到<e />之前。

我最接近的是:

echo .. | xml ed -m "//d" "//e"

产生:

<e>
  <d/>
</a>

不幸的是,这是手册给出的例子。

echo .. | xml ed -m "//d" "//x"

<d />放在最后,这不是正确的地方。

我试图让preceding-sibling工作(如果确实这是正确的方法),但同时:

echo .. | xml sel -t -c "//e/preceding-sibling::*[1]"

<c />中的结果,该查询不能用作移动目的地(它抱怨移动目的地不是单个节点),也不是真的,因为最好的情况是它最终会在{} {1}}。

我不确定<c />是否是错误的方法,如果有一种形式的XPATH指向元素之间的位置而不是元素。

编辑:有趣的是,插入的工作更像我的期望,插入在使用xpath选取元素之前传递的内容:

ed -m

不幸的是,传递的值(上面$ xml ed -i "//c" -t elem -n "foo" -v "bar" test.xml <?xml version="1.0"?> <x> <a/> <d/> <b/> <foo>bar</foo> <c/> <e/> <f/> </x> )不能是XML,所以我可以用sel从某个地方选择它,然后用我不认为的命令注入它。

1 个答案:

答案 0 :(得分:1)

使用ed似乎很容易。如果是的话,我没有看到它。 (我不经常使用xmlstarlet。)

您可能需要使用XSLT ...

XSLT 1.0

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

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

  <xsl:template match="c">
    <xsl:copy-of select="."/>
    <xsl:copy-of select="../d"/>
  </xsl:template>

</xsl:stylesheet>

命令行

$ xml tr test.xsl test.xml
<?xml version="1.0"?>
<x>
  <a/>
  <b/>
  <c/>
  <d/>
  <e/>
  <f/>
</x>