向上移动XML节点的子节点
想象一下我有以下XML文件:
<a>之前<b>中间</ b>之后</a>
我想将其转换成这样的东西:
<a>在中间之前</a>
换句话说,我想获取某个节点的所有子节点,然后按顺序将它们移动到父节点。就像执行以下命令:" mv ./directory/*。",但是对于xml节点。
我想通过使用UNIX命令行工具来做到这一点。我一直在尝试xmlstarlet,它是一个功能强大的命令行XML操纵器。我试图做这样的事情,但是没有用
回声" <a>之前<b>中间</ b>之后</a>" | xmlstarlet ed -m" // b / *"" .."
更新:XSLT模板很好,因为可以从命令行调用它们。
我的目标是"从XHTML页面删除链接",换句话说,用link标签的内容替换链接所在的位置。
解决方案
在XSLT中,我们可以编写:
<xsl:template match="a"><a><xsl:apply-templates /></a></xsl:template> <xsl:template match="a/b"><xsl:value-of select="."/></xsl:template>
然后我们会得到:
<a>beforemiddleafter</a>
因此,如果我们想以一种简单的方式执行此操作,则只需创建一个XSL样式表并通过它运行XML文件。
我意识到这不是我们说的那样(使用Unix命令行)。我对Unix一无所知,所以也许其他人可以填补空白。可以执行上述操作的某种命令行调用。
输入文件示例(test.xml):
<?xml version="1.0" encoding="UTF-8"?> <test> <x>before<y>middle</y>after</x> <a>before<b>middle</b>after</a> <a>before<b>middle</b>after</a> <x>before<y>middle</y>after</x> <a>before<b>middle</b>after</a> <embedded>foo<a>before<b>middle</b>after</a>bar</embedded> </test>
XSLT样式表(collapse.xsl:
<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()"/> </xsl:copy> </xsl:template> <xsl:template match="a"> <xsl:copy> <xsl:value-of select="."/> </xsl:copy> </xsl:template> </xsl:stylesheet>
使用XmlStarlet运行
xml tr collapse.xsl test.xml
产生:
<?xml version="1.0"?> <test> <x>before<y>middle</y>after</x> <a>beforemiddleafter</a> <a>beforemiddleafter</a> <x>before<y>middle</y>after</x> <a>beforemiddleafter</a> <embedded>foo<a>beforemiddleafter</a>bar</embedded> </test>
样式表中的第一个模板是基本的身份转换(只需复制整个输入XML文档)。第二个模板专门匹配我们要"折叠"的元素,仅复制标签并插入元素的字符串值(=后代节点的字符串值的串联)。
你有试过吗?
file.xml
<r> <a>start<b>middle</b>end</a> </r>
template.xsl
<xsl:template match="/"> <a><xsl:value-of select="r/a" /></a> </xsl:template>
输出
<a>startmiddleend</a>
如果实际目标是从网页上删除链接,则应使用这样的样式表,该样式表匹配所有XHTML<a>
元素(我假设我们使用的是XHTML?),只需将模板应用于他们的内容:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:h="http://www.w3.org/1999/xhtml" exclude-result-prefixes="h"> <!-- Don't copy the <a> elements, just process their content --> <xsl:template match="h:a"> <xsl:apply-templates /> </xsl:template> <!-- identity template; copies everything by default --> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> </xsl:stylesheet>
此样式表将处理我们要保留在<a>元素内嵌套的某些内容的情况,例如:
<p>Here is <a href="....">some <em>linked</em> text</a>.</p>
我们希望将其显示为:
<p>Here is some <em>linked</em> text.</p>
它将处理链接嵌套在通常的父级(" <p>"元素)和" <a>"元素之间的意外元素内的情况,例如:
<p>Here is <em>some <a href="...">linked</a> text</em>.</p>
使用xmlstarlet:
xmlstr='<a>before<b>middle</b>after</a>' updatestr="$(echo "$xmlstr" | xmlstarlet sel -T -t -m "/a/b" -v '../.' -n | sed -n '1{p;q;}')" echo "$xmlstr" | xmlstarlet ed -u "/a" -v "$updatestr"