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

标签 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 /> ,该查询不能用作移动目的地(它提示移动目的地不是单个节点),也不是真的,因为最好的情况是它最终会在 <c /> 内结束。 .

我不确定 ed -m是错误的方法,如果有一种形式的 XPATH 指向元素之间的位置而不是元素。

编辑: 有趣的是,插入的工作方式更像我期望的那样,在使用 xpath 选择的元素之前插入您传递给它的内容:

$ 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>

不幸的是,传递的值(上面的 bar)不能是 XML,所以我可以用 sel 从某个地方挑选它,然后用我不认为的这个命令将它注入(inject)。

最佳答案

这看起来应该很容易使用 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>

关于XMLStarlet:使用 xpath 将一个元素移动到另一个元素之前,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42959317/

相关文章:

c# - 套接字流不包含整个响应

xml - 为 XSLFO 中的文本设置背景颜色

python - 在 scrapy 中匹配多个 <p> 标签

xml - 声明一个 xsl 变量并为其赋值

仅当源属性存在时,XSLT 才向节点添加属性

xmlstarlet - 删除一个 xml 元素 - shell 脚本

c# - 如何防止 System.Xml.XmlDocument 转义属性值

c# - 如何从流中将新元素附加到 Xml

xml - 使用 sed 创建 XML 数组

xpath - 测试 XML 属性