XSLT - 屏蔽数据 - 以其他标签为条件

Posted

技术标签:

【中文标题】XSLT - 屏蔽数据 - 以其他标签为条件【英文标题】:XSLT - masking data - Conditional on other tags 【发布时间】:2021-11-11 09:33:29 【问题描述】:

我正在尝试屏蔽存在某些特定标签的 xml 文档。我创建了一个包含 saxon9he 作为依赖项的 java 应用程序。

<dependencies>
<dependency>
    <groupId>net.sf.saxon</groupId>
    <artifactId>saxon9he</artifactId>
    <version>9.4.0.4</version>
</dependency>
</dependencies>

我有多个用例,有些是直截了当的,但有些是有条件的。假设以下给定的&lt;Prsn&gt; 标签出现在多个不同的位置:

输入xml sn-p

<ns3:Prsn>
  <ns3:FrstNm>BDMFN</ns3:FrstNm>
  <ns3:Nm>BDMSN</ns3:Nm>
  <ns3:BirthDt>2000-01-02</ns3:BirthDt>
  <ns3:Othr>
    <ns3:Id>GB1592102</ns3:Id>
    <ns3:SchmeNm>
      <ns3:Cd>CCPT</ns3:Cd>
    </ns3:SchmeNm>
  </ns3:Othr>
</ns3:Prsn>

需要的转换

在上面提供的 XML 中,我们需要屏蔽一些标签 [FrstNmNmBirthDt](删除实际的来自这些标签的数据并用 # 替换每个字符),顺便说一句,到目前为止我已经实现了。

需要帮助

棘手的部分是当我们有标签 &lt;Othr&gt;&lt;SchmeNm&gt;&lt;Cd&gt; 可以有值 [NIND, CCPT, CONCAT] 时,我们需要屏蔽 &lt;Othr&gt;&lt;id&gt;,但除了 &lt;Othr&gt;&lt;SchmeNm&gt;&lt;Cd&gt; 中的任何其他值NIND、CCPT、CONCAT 然后&lt;Othr&gt;&lt;id&gt; 没有变化。

Transformation.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes" />

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

  <xsl:template match="*[local-name()='FrstNm']">
    <xsl:copy>
      <xsl:value-of select="replace(text(), '[A-Za-z]','#')" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[local-name()='Nm']">
    <xsl:copy>
      <xsl:value-of select="replace(text(), '[A-Za-z]','#')" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[local-name()='BirthDt']">
    <xsl:copy>
      <xsl:value-of select="replace(text(), '[0-9]','#')" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

【问题讨论】:

XSLT 1.0 中不存在replace() 函数。 Saxon 9.4 很久以前了:当前版本是10.5 借助 Saxon,您可以使用 XSLT 2.0 语法 match="*:Nm" 【参考方案1】:

如果您想进行基于正则表达式的搜索和替换,您需要的最低 XSLT 版本是 XSLT 2.0。

另外,不要使用local-name()。为命名空间 URI 注册一个前缀并使用它。前缀不必与 XML 文档匹配,只要命名空间 URI 相同即可。

输入:

<ns3:Prsn xmlns:ns3="some-namespace-uri">
  <ns3:FrstNm>BDMFN</ns3:FrstNm>
  <ns3:Nm>BDMSN</ns3:Nm>
  <ns3:BirthDt>2000-01-02</ns3:BirthDt>
  <ns3:Othr>
    <ns3:Id>GB1592102</ns3:Id>
    <ns3:SchmeNm>
      <ns3:Cd>CCPT</ns3:Cd>
    </ns3:SchmeNm>
  </ns3:Othr>
</ns3:Prsn>

XSLT 2.0+:

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:person="some-namespace-uri"
>
  <xsl:output method="xml" indent="yes" />

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

  <xsl:template match="person:FrstNm|person:Nm|person:BirthDt">
    <xsl:copy>
      <xsl:value-of select="replace(text(), '[A-Za-z0-9]', '#')" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

输出:

<ns3:Prsn xmlns:ns3="some-namespace-uri">
  <ns3:FrstNm>#####</ns3:FrstNm>
  <ns3:Nm>#####</ns3:Nm>
  <ns3:BirthDt>####-##-##</ns3:BirthDt>
  <ns3:Othr>
      <ns3:Id>GB1592102</ns3:Id>
      <ns3:SchmeNm>
         <ns3:Cd>CCPT</ns3:Cd>
      </ns3:SchmeNm>
  </ns3:Othr>
</ns3:Prsn>

如果您只有 XSLT 1.0,您可以使用translate()。但这要求您明确列出所有个可能的输入字符:

<xsl:template match="person:FrstNm|person:Nm|person:BirthDt">
  <xsl:copy>
    <xsl:value-of select="tanslate(
      text(),
      'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-add-everything-else',
      '##################################################################################'
    )" />
  </xsl:copy>
</xsl:template>

或者你选择更简单的东西:

<xsl:template match="person:FrstNm|person:Nm|person:BirthDt">
  <xsl:copy>
    <xsl:text>[redacted]</xsl:text>
  </xsl:copy>
</xsl:template>

棘手的部分是当我们有标签&lt;Othr&gt;&lt;SchmeNm&gt;&lt;Cd&gt;,它可以有值[NIND,CCPT,CONCAT],我们需要屏蔽&lt;Othr&gt;&lt;id&gt;,但是&lt;Othr&gt;&lt;SchmeNm&gt;&lt;Cd&gt;中的任何其他值除了NIND,CCPT,CONCAT然后没有更改&lt;Othr&gt;&lt;id&gt;

这很容易。在 XSLT 1.0+ 这工作:

<xsl:template match="
  person:FrstNm|person:Nm|person:BirthDt|person:Id[
    ../person:SchmeNm/person:Cd = 'NIND' or 
    ../person:SchmeNm/person:Cd = 'CCPT' or
    ../person:SchmeNm/person:Cd = 'CONCAT'
  ]
">

甚至这个:

<xsl:template match="
  person:FrstNm|person:Nm|person:BirthDt|person:Id[
    contains('|NIND|CCPT|CONCAT|', concat('|', ../person:SchmeNm/person:Cd, '|'))
  ]
">

在 XSLT 2.0+ 中,您可以使用序列:

<xsl:template match="
  person:FrstNm|person:Nm|person:BirthDt|person:Id[
    ../person:SchmeNm/person:Cd = ('NIND', 'CCPT', 'CONCAT')
  ]
">

【讨论】:

如果值为 NIND 或 CCPT 或 CONCAT,我想根据 屏蔽 @truekiller 查看更新。 @truekiller 对于正则表达式方法,还要考虑比[a-zA-Z0-9] 更好的东西。 \w 运作良好,涵盖所有 Unicode 字母和数字。 另见:***.com/a/68407659/3016153

以上是关于XSLT - 屏蔽数据 - 以其他标签为条件的主要内容,如果未能解决你的问题,请参考以下文章

如何屏蔽数据库里写的HTML标签 使之在datalist显示内容时不显示标签里的内容

忙等待中的互斥

特定格式的数据屏蔽

配置单元中的正则表达式替换解决方案以屏蔽前 6 个字符

nginx或dns url基于路径重写或屏蔽

如何用css屏蔽a标签title