用 XSLT 删除 XML 示例文件中的敏感内容

Uche Ogbuji, 首席顾问, Fourthought Inc.

2006 年 5 月 08 日

消除内容

清单 1 (kill-content.xslt) 中的 XSLT 脚本可以删除所有的文本节点和属性值,仅留下节点结构骨架。


清单 1 (kill-content.xslt). 清除字符数据的 XSLT 脚本

<?xml version="1.0" encoding="utf-8"?>
<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="@*">
    <xsl:attribute namespace="{namespace-uri()}" name="{name()}"/>
  </xsl:template>

  <xsl:template match="text()"/>

</xsl:stylesheet>


<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>

从第一个模板可以看出,与很多有用的脚本一样,这里也使用了恒等变换。第二个模板将所有属性复制到输出中,但省略了属性值。第三个模板删除了所有文本节点。所有其他节点类型,包括元素,都由第一个模板处理,该模板将节点的基本结构复制到输出中。清单 2 是用该脚本处理的一个示例文件。


清单 2 (patients.xml). 示例 XML 文件

<?xml version="1.0" encoding="iso-8859-1"?>
<patients>
  <patient id='ep' admitted="2003-06-10">
    <name>Ezra Pound</name>
    <address>
      <street>45 Usura Place</street>
      <city>Hailey</city>
      <province>ID</province>
    </address>
    <condition>ore infectus</condition>
  </patient>
  <patient id='tse' admitted="2003-06-20">
    <name>Thomas Eliot</name>
    <address>
      <street>3 Prufrock Lane</street>
      <city>Stamford</city>
      <province>CT</province>
    </address>
    <condition>Sartor resartus</condition>
  </patient>
  <patient id="co" admitted="2004-11-15">
    <name>Christopher Okigbo</name>
    <address>
      <street>7 Heaven's Gate</street>
      <city>Idoto</city>
      <province>Anambra</province>
    </address>
    <condition>caeli porta quaerit</condition>
  </patient>
</patients>


如果将 清单 1 中的 XSLT 脚本应用到 清单 2 中的 XML 例子,就会得到下面的 XML(忽略了 XML 声明)。


<patients><patient id="" admitted=""><name/><address><street/><city/>...

可以看到,结果中保留了基本的元素和属性结构,但是没有内容了。

增加空格

如果彻底删除字符数据过于极端,希望至少保留每个节点的长度,可以使用 清单 1 的一个变体。清单 3 中的 XSLT 脚本用长度相同但仅包含空格的节点代替所有字符数据。


清单 3 (blank-content.xslt). 将所有字符数据替换为空白内容的 XSLT 脚本

<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:x="http://ns.ogbuji.net/articles"
>

  <x:wsbuffer xml:space="preserve">                        </x:wsbuffer>
  <xsl:variable name="wsbuf" select="string(document('')/*/x:wsbuffer)"/>

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

  <xsl:template match="@*">
    <xsl:attribute namespace="{namespace-uri()}" name="{name()}">
      <xsl:value-of select="translate(., ., $wsbuf)"/>
    </xsl:attribute>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:value-of select="translate(., ., $wsbuf)"/>
  </xsl:template>

</xsl:transform>


关键是顶层的扩展元素 x:wsbuffer,它提供了替换操作中所使用的空白字符内容。由于格式方面的原因,我减少了空格,但是该元素可以增加更多的空格,因为原始数据中的所有字符数据节点都用同样长度的空白替换,最大长度为 x:wsbuffer 中的字符数。xml:space 属性用于防止 XSLT 处理程序压缩 x:wsbuffer 中的空白。x:wsbuffer 实际上可使用任何内容,作为字符数据的常备替代文本。如果使用任何非空白字符,就不需要 xml:space 属性了。

通过自引用 XSLT 文档(使用 document('') 的特殊形式),变量 wsbuf 设置为替换文本。转换的其他部分与 清单 1 类似,只不过没有删除文本,而是用 wsbuf 中相同位置的字符替换每个字符。与 清单 1 一样,最终所有的输出内容都是空白。如果希望改变结果可以尝试修改 x:wsbuffer 的内容。

如果将 清单 3 中的 XSLT 脚本应用于 清单 2 中的 XML,就会得到下面的 XML。


<patients>   <patient id="  " admitted="          ">     <name>          </name>...

结束语

本文介绍了如何修改 XML 文档,在保留基本结构不变的同时删除或者改变内容以免泄漏敏感信息。这种技术有一定的局限性,主要是由于 XSLT 本身的局限性造成的。特别需要指出的是,如果请求解决的问题涉及到字符数据本身的特点(比方说,处理字符实体的 bug),如此处理的示例文件就丢失了关键信息。记住,XSLT 还丢失了 XML 文件中的其他信息,如顶层声明、实体引用和 CDATA 节。如果这些内容对解决问题很重要,就不能使用 XSLT 清理文件。我遇到很多情形使用这些脚本就足够了,因此这些技术仍然值得学习。如果愿意使用 EXSLT 扩展,还可以进一步控制字符数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值