如何在 XML 文件中查找特定标签部分?

如何在 XML 文件中查找特定标签部分?

我的文件的最后几行/usr/share/glib-2.0/schemas/org.gnome.Vino.gschema.xml

<schemalist>
  <schema>
   <!-- some other tags -->

    <key name='notify-on-connect' type='b'>
      <summary>Notify on connect</summary>
      <description>
        If true, show a notification when a user connects to the system.
      </description>
      <default>true</default>
    </key>

    <key name='enabled' type='b'>
      <summary>Enable remote access to the desktop</summary>
      <description>
      If true, allows remote access to the desktop via the RFB
      protocol. Users on remote machines may then connect to the
      desktop using a VNC viewer.
      </description>
      <default>false</default>
    </key>
  </schema>
</schemalist>

如果我想要grep这一段:

<key name='enabled' type='b'>
  <summary>Enable remote access to the desktop</summary>
  <description>
  If true, allows remote access to the desktop via the RFB
  protocol. Users on remote machines may then connect to the
  desktop using a VNC viewer.
  </description>
  <default>false</default>
</key>

我应该如何使用该grep命令来实现这一目标?

答案1

由于您给出的示例是一个有效的 XML 文件,因此我将使用xqXML 解析器工具来处理该文件,该工具是yq安装包

xq -x --xml-root key '
    .schemalist.schema.key[] | select(."@name" == "enabled")
' infile.xml

如果“key”标签的“@name”属性等于“enabled”,则选择“key”标签。

来自xq -h

--xml-输出,-x
将 jq JSON 输出转码回 XML 并发出
--xml-根 XML_ROOT
当转码回 XML 时,将输出封装在具有此名称的元素中

答案2

由于您正在处理有效的 XML,因此您可以使用xmlstarlet

xmlstarlet sel -t -c "/schemalist/schema/key[@name='enabled']" infile.xml

这将查询 ( ) XML 文档并打印XPATH 元素的sel副本,其中选择了属性设置为 的XML 节点。-c/schemalist/schema/keynameenabled

您的示例的输出:

<key name="enabled" type="b">
      <summary>Enable remote access to the desktop</summary>
      <description>
      If true, allows remote access to the desktop via the RFB
      protocol. Users on remote machines may then connect to the
      desktop using a VNC viewer.
      </description>
      <default>false</default>
    </key>

答案3

需要明确的是:

这很可能是某些能够理解 XML 文档的工具的工作,而不是grep诸如此类的工具的工作。关于这一点有很好的答案。


也许:

grep

使用 perl-regexp 和其他补充。

grep -Pzo "(?s)\N*<key name='enabled'.*<\/key>\n" the_file.xml

或者有一点限制(不捕获前导空白):

grep -zo "<key name='enabled'.*<\/key>."

awk

awk '
/<key name='\''enabled'\''/ { p=1 }
p { print $0 }
p && /<\/key>/ { exit }
' the_file.xml

或者

awk "/<key name='enabled'/,/<\/key>/" the_file.xml

sed

sed -n '/<key name='\''enabled'\''/,/<\/key>/p' the_file.xml

答案4

获得所需输出的另一种方法是使用 XSL(可扩展样式表语言)xsltproc- 如果您使用 GNOME 桌面,则默认安装该语言 - 将输入文档转换为所需文档(输出)。

这是样式表:

$ cat transform.xsl
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method='xml' omit-xml-declaration='yes' />

<xsl:template match="/schemalist/schema/key[@name='enabled']">
    <xsl:copy-of select="." />
</xsl:template>

<xsl:template match='text()|@*'/>

</xsl:stylesheet>

这是输出:

$ xsltproc transform.xsl input.xml
<key name="enabled" type="b">
      <summary>Enable remote access to the desktop</summary>
      <description>
      If true, allows remote access to the desktop via the RFB
      protocol. Users on remote machines may then connect to the
      desktop using a VNC viewer.
      </description>
      <default>false</default>
    </key>
$

相关内容