【问题标题】:Using SED to delete all XML elements which have certain values使用 SED 删除所有具有特定值的 XML 元素
【发布时间】:2017-04-05 00:17:32
【问题描述】:

我们使用一种工具(pentaho 数据集成),它使用 XML 作为其文件的布局。它在这些文件中存储了太多信息(如连接信息)。在将文件推送到 Git 之前,我想清除所有使用 JNDI 的连接块。如果我使用 XSLT(这可能是一种可能性),实体将得到解决。这将导致 Git 在我每次进行少量编辑时都会看到大量更改 - 显然是不可取的。

我有一个包含以下行的 XML 文件:

<connections>
   <connection>
      <name>connection1</name>
      <server/>
      <type>POSTGRESQL</type>
      <access>JNDI</access>
      <database>connections&#x2f;test&#x2f;connection1</database>
      <port>-1</port>
      <username/>
      <password>Encrypted </password>
   </connection>
   <connection>
      <name>test</name>
      <server>asdf</server>
      <type>ORACLE</type>
      <access>Native</access>
      <database>asdf</database>
      <port>1521</port>
      <username>asdf</username>
      <password>zcv</password>
   </connection>
</connections>

我想把它简化为:

<connections>
   <connection>
      <name>test</name>
      <server>asdf</server>
      <type>ORACLE</type>
      <access>Native</access>
      <database>asdf</database>
      <port>1521</port>
      <username>asdf</username>
      <password>zcv</password>
   </connection>
</connections>

我不能使用 XSLT 解析器(例如 xmlstarlet),因为它会解析实体引用(&amp;#x2f; 变为 /)。

我已经用 sed 试过了:

sed -ne '/<connection>/+.*/<access>/JNDI<\/access>/[\s\S]+.*<\/connection>/d'

但没有运气。

【问题讨论】:

  • 你不想使用 sed 来处理 XML。
  • 为什么解析实体是个问题?如果是 XML,那么这两种表示是等价的。如果它不是 XML,则问题被错误标记(并且您遇到更大的问题)。无论哪种方式,sed 都可能是适合这项工作的错误工具。
  • 我们使用一种工具(pentaho 数据集成),它使用 XML 作为其文件的布局。它在这些文件中存储了太多信息(如示例中解释的连接)。在将文件推送到 GIT 之前,我想清除所有使用 JNDI 的连接块。如果我使用 XSLT(这可能是一种可能性),实体将得到解决。这将导致 GIT 在您每次要上传微小更改时看到大量更改。不用说,这是我们不想要的。
  • 谢谢!好主意,完成了.. :)

标签: xml sed


【解决方案1】:

sed 不具备处理 XML 的能力。如果您想正确执行,请使用 XML 感知工具。

xsltproc 就是这样一个工具。将它与这样的 XSL 转换一起使用:

<!-- dropJNDI.xsl -->    
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

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

    <!-- except connection nodes with access = JNDI, do not output them --> 
    <xsl:template match="connection[access = 'JNDI']" />
</xsl:transform>

用法

xsltproc dropJNDI.xsl input.xml > output.txt

【讨论】:

  • 我们使用一种工具(pentaho 数据集成),它使用 XML 作为文件的布局。它在这些文件中存储了太多信息(如示例中解释的连接)。在将文件推送到 GIT 之前,我想清除所有使用 JNDI 的连接块。如果我使用 XSLT(这可能是一种可能性),实体将得到解决。这将导致 GIT 在您每次要上传微小更改时看到大量更改。不用说,这是我们不想要的。
  • 嗯。如果您总是通过 XSLT 作为构建过程的常规部分传递它,那么所有实体都将被一致地解码。使用正则表达式是自找麻烦,我强烈反对。
【解决方案2】:

这可能对你有用(GNU sed):

sed '/<connection>/!b;:a;N;/<\/connection>/!ba;/<access>JNDI<\/access>/d' file

这会过滤掉可以访问JNDI 的连接。但是,只有当 XML 按原样呈现时才会这样做。

【讨论】:

  • 感谢您的回答.. 我试过这个并收到以下消息:sed: 1: "/&lt;connection&gt;/!b;:a;N;/ ...": undefined label ';:a;N;/&lt;\/connection&gt;/!ba;/&lt;access&gt;JNDI&lt;\/access&gt;/d'
  • @RobSmienk 我建议用单引号将命令括起来,或者使用-e 开关分隔每个命令,即sed -e '/&lt;connection&gt;/!b' -e ':a' -e 'N' -e '/&lt;\/connection&gt;/!ba' -e '/&lt;access&gt;JNDI&lt;\/access&gt;/d' file
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-11
  • 2019-07-27
  • 1970-01-01
  • 2018-05-12
  • 1970-01-01
  • 2010-10-15
相关资源
最近更新 更多