XMLStarlet:使用 xpath 将一个元素移动到另一个元素之前
XMLStarlet: Using xpath to move an element to be before another one
给定:
<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从某个地方把它挑出来,然后用我不认为的这个命令注入它。
这看起来应该很容易使用 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>
给定:
<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从某个地方把它挑出来,然后用我不认为的这个命令注入它。
这看起来应该很容易使用 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>