删除emacs中某种类型的所有标签

时间:2013-02-22 20:26:25

标签: xml regex emacs

我有一个XML文件。只是阅读,我可以告诉你很兴奋。

现在我想完全删除一些标签:

<qwerty option=1>
<nmo>sdfsdf</nmo>
<blue>sdfsdf</blue>
</qwerty>

这是个大文件。如何删除所有标记nmoblue,包括其内容?在Emacs中,或者我的mac可以使用的任何其他内容。

3 个答案:

答案 0 :(得分:4)

Emacs具有用于导航符号表达式或“sexps”的命令。在xml-mode中,sexp导航命令适用于标记。您可以导航到开头<,按 CMf forward-sexp)导航到标记的末尾,或按 CMk ({{ 1}})杀死它。变量kill-sexp控制您是在开始标记的末尾(默认值)还是结束标记的结尾。我更喜欢后者。

要删除这些标记,首先使用 M-x customize-variable nxml-sexp-element-flag 设置nxml-sexp-element-flag。接下来,搜索您要杀死的标记,将该点移动到开头nxml-sexp-element-flag并按 C-M-k 。将此全部包装在一个宏中,并重复整个文件,直到搜索失败。

答案 1 :(得分:3)

我假设您的xml文件格式正确。而且我还假设与您的示例相反,您的“真实”数据比每行一个标记稍微复杂一些(除了根目录之外)。否则,我们是否同意删除包含给定标记的行这么简单?

这是一个可以解决问题的函数的命题:

(defun my-remove-tag (tag)
  (save-excursion
     (let ((case-fold-search nil))
       (while (search-forward-regexp (concat "<" tag "[^\\>]*>"))
     (delete-region
      (match-beginning 0)
      (search-forward (concat "</" tag ">")))))))

调用此功能,您可以查找nmoblueqwerty标记,如下所示:

(my-remove-tag "nmo")
(my-remove-tag "qwerty")

理由是寻找一个开始标记然后寻找结束标记,并删除中间的所有内容。标记的属性可以在中间,并且此函数处理包含属性的开始标记。

一旦功能完成,将禁用并恢复区分大小写。此外,Emacs Point将使用通常的宏恢复:save-excusion

更新

我删除了外部let。无需手动恢复case-fold-search值,let绑定只会影响全局值,它通过“unhadowing”恢复。

答案 2 :(得分:3)

我认为更通用的方法是使用更多面向XML的工具,比如XSL(T)(不要害怕,没人喜欢),但如果你必须工作它会派上用场使用XML(不要害怕,也没有人喜欢)。

所以,我们走了:

这是你的XSL文件(它复制原始XML中的所有内容,并用空行替换你想要删除的节点。最后,它打印出来,使它看起来更漂亮,然后如果你用它替换它一个正则表达式。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                exclude-result-prefixes="msxsl"
                >
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/> 

  <!-- Copy everything -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- Find any node named nmo or blue and replace it with nothing -->
  <xsl:template match="nmo | blue"/>
</xsl:stylesheet>

这是我以前测试的例子:

<?xml version="1.0" encoding="utf-8"?>
<nodes>
  <qwerty option="1">
    <nmo>sdfsdf</nmo>
    <blue>sdfsdf</blue>
  </qwerty>
  <nodes>
    <qwerty option="1">
      <nmo>sdfsdf</nmo>
      <blue>sdfsdf</blue>
    </qwerty>
  </nodes>
  <nodes>
    <qwerty option="1">
      <nmo>sdfsdf</nmo>
      <blue>sdfsdf</blue>
    </qwerty>
    <other node=""/>
    <nodes>
      <qwerty option="1">
        <nmo>sdfsdf</nmo>
        <blue>sdfsdf</blue>
      </qwerty>
      <qwerty option="1">
        <nmo>sdfsdf</nmo>
        <blue>sdfsdf</blue>
      </qwerty>
      <qwerty option="1">
        <nmo>sdfsdf</nmo>
        <blue>sdfsdf</blue>
      </qwerty>
    </nodes>
  </nodes>
</nodes>

这是我收到的输出:

<?xml version="1.0"?>
<nodes>
  <qwerty option="1"/>
  <nodes>
    <qwerty option="1"/>
  </nodes>
  <nodes>
    <qwerty option="1"/>
    <other node=""/>
    <nodes>
      <qwerty option="1"/>
      <qwerty option="1"/>
      <qwerty option="1"/>
    </nodes>
  </nodes>
</nodes>

注意它是如何关闭qwerty节点的。

获取此命令的命令行如下:

xsltproc ./remove-nodes.xsl ./nodes-to-be-removed.xml > result.xml 

你可以从Emacs的shell运行它,或者使用任何Emacs的函数来调用它/用它创建一个进程,依此类推。 man xsltproc了解更多信息 - 它的用法非常基本。它安装在我的Fedora上,但我想可以认为,由于全世界普遍存在XML,它可能已经安装在Mac上,或者必须以某种方式安装。