1

想象一下,我有以下 XML 文件:

<a>之前<b>中间</b>之后</a>

我想把它转换成这样的东西:

<a>前中后</a>

换句话说,我想获取某个节点的所有子节点,并将它们按顺序移动到父节点。这就像执行以下命令:“mv ./directory/* .”,但用于 xml 节点。

我想在使用 unix 命令行工具时做到这一点。我一直在尝试使用 xmlstarlet,它是一个强大的命令行 XML 操纵器。我尝试做这样的事情,但它不起作用

echo "<a>之前<b>中间</b>之后</a>" | xmlstarlet ed -m "//b/*" ".."

更新:XSLT 模板很好,因为它们可以从命令行调用。

我的目标是“从 XHTML 页面中删除链接”,换句话说,用链接标记的内容替换链接所在的位置。

4

5 回答 5

3

示例输入文件 (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 文档)。第二个模板专门匹配您想要“折叠”的元素,并且只复制标签并插入元素的字符串值(=后代节点的字符串值的串联)。

于 2008-09-24T05:22:55.783 回答
2

在 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一无所知,所以也许其他人可以填补空白,例如。某种可以执行上述操作的命令行调用。

于 2008-09-23T22:04:31.080 回答
2

如果您的实际目标是从网页中删除链接,那么您应该使用这样的样式表,它匹配所有 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>
于 2008-09-25T08:44:15.713 回答
1

使用 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"
于 2010-07-04T07:55:36.513 回答
0

你试过这个吗?

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>

output

<a>startmiddleend</a>
于 2008-09-24T13:50:06.283 回答