使用XSLT的CDATA XML屏蔽应返回具有少量屏蔽字段的相同XML

时间:2015-01-28 03:29:01

标签: java xml xslt

我需要使用XSLT在XML内部屏蔽XML中的少数字段 因此,结果XML应该与输入XML相同,但很少有文件被XSLT掩盖 我按照预期的this链接进行了屏蔽,但生成的XML格式不同 我从SO那里尝试了许多其他解决方案,它们几乎以其他格式输出新的XML / HTML,这与输入XML不同。
请查看以下示例以获得更好的说明   输入带有CDATA内容的XML。

<XML>
  <LogLevel>info</LogLevel>
  <Content><![CDATA[ <Msg>
        <AccountNo>2701000098983</AccountNo>
        <ApplName>Testing</ApplName>
       </Msg>]]></Content>
  <Date>20140909</Date>
</XML>

输出XML应为:

   <XML>
      <LogLevel>info</LogLevel>
      <Content><![CDATA[ <Msg>
            <AccountNo>XXXXXXXXXX983</AccountNo>
            <ApplName>Testing</ApplName>
           </Msg>]]></Content>
      <Date>20140909</Date>
   </XML>

编辑:
我使用了以下XSLT

 <xsl:template match="node()">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
    <xsl:template match="text()">
        <xsl:choose>
            <xsl:when test="contains(.,'&lt;AccountNo&gt;')">
                <!-- This is the CDATA that I want to mask and write back out as CDATA -->
                <xsl:variable name="tcontent">
                    <xsl:value-of
                        select="substring-after(substring-before(.,'&lt;/AccountNo&gt;'),'&lt;AccountNo&gt;') " />
                </xsl:variable>
                <xsl:text disable-output-escaping="yes">&lt;![CDATA[&lt;AccountNo&gt;</xsl:text>
                <xsl:call-template name="maskVariable">
                    <xsl:with-param name="tvar" select="$tcontent" />
                </xsl:call-template>
                <xsl:text disable-output-escaping="yes">&lt;/AccountNo&gt;]]&gt;</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
<xsl:template name="maskVariable">
    <xsl:param name="tvar" />
    <xsl:variable name="length" select="string-length($tvar)" />
    <xsl:choose>
        <xsl:when test="$length > 3">
            <xsl:value-of
                select="concat ('************', substring($tvar,$length - 1, 2))" />
        </xsl:when>
        <xsl:when test="$length > 1">
                ***
            </xsl:when>
            <xsl:otherwise />
        </xsl:choose>
    </xsl:template>

使用此XSLT的输出是:

<LogLevel>info</LogLevel>
<Content><![CDATA[<AccountNo>************02</AccountNo>]]></Content>
<Date>20140909</Date>

此处输出中仅显示屏蔽输出 如何使代码的其他部分显示? 请介绍一下如何做到这一点? 任何帮助都非常感谢。

2 个答案:

答案 0 :(得分:1)

为什么不尝试:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="Content">
    <xsl:copy>
        <xsl:value-of select="substring-before(.,'&lt;AccountNo&gt;')" />
        <xsl:text>&lt;AccountNo&gt;</xsl:text>
        <xsl:variable name="acct-num" select="substring-before(substring-after(.,'&lt;AccountNo&gt;'), '&lt;/AccountNo&gt;')" />
        <xsl:value-of select="concat('************', substring($acct-num, string-length($acct-num) - 2))" />
        <xsl:text>&lt;/AccountNo&gt;</xsl:text>
        <xsl:value-of select="substring-after(.,'&lt;/AccountNo&gt;')" />
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

应用于您的输入,结果将是:

<?xml version="1.0" encoding="UTF-8"?>
<XML>
   <LogLevel>info</LogLevel>
   <Content> &lt;Msg&gt;
        &lt;AccountNo&gt;************983&lt;/AccountNo&gt;
        &lt;ApplName&gt;Testing&lt;/ApplName&gt;
       &lt;/Msg&gt;</Content>
   <Date>20140909</Date>
</XML>

或者,您可以使用:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" cdata-section-elements="Content"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="Content">
    <xsl:copy>
        <xsl:variable name="content">
            <xsl:value-of select="substring-before(.,'&lt;AccountNo&gt;')" />
            <xsl:text>&lt;AccountNo&gt;</xsl:text>
            <xsl:variable name="acct-num" select="substring-before(substring-after(.,'&lt;AccountNo&gt;'), '&lt;/AccountNo&gt;')" />
            <xsl:value-of select="concat('************', substring($acct-num, string-length($acct-num) - 2))" />
            <xsl:text>&lt;/AccountNo&gt;</xsl:text>
            <xsl:value-of select="substring-after(.,'&lt;/AccountNo&gt;')" />
        </xsl:variable>
        <xsl:value-of select="$content" disable-output-escaping="yes"/> 
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

生产:

<?xml version="1.0" encoding="UTF-8"?>
<XML>
<LogLevel>info</LogLevel>
<Content><![CDATA[ <Msg>
        <AccountNo>************983</AccountNo>
        <ApplName>Testing</ApplName>
       </Msg>]]></Content>
<Date>20140909</Date>
</XML>

尽管这可能不适用于每个处理器(经测试可与Xalan 2.7.1配合使用:http://xsltransform.net/jyH9rMk)。

答案 1 :(得分:0)

CDATA部分内的内容是伪装成文本的XML。 XSLT擅长转换XML,它不擅长转换文本,尤其是具有复杂语法的文本。所以我的方法是:从外部XML文档中提取文本,将其解析为XML,使用XSLT(在节点上而不是在标记上工作的真正XSLT)对其进行转换,将其序列化为文本,然后将文本填充回文本中。原始(外部)XML文档。

原始XSLT 1.0无法在单个样式表中执行此操作。您需要使用函数parse()和serialize()将词法XML转换为节点树,然后再返回。它们在某些处理器(例如Saxon)中作为扩展提供,它们可以作为XPath 3.0中的标准函数使用,并且它们可以在大多数其他处理器中作为简单的扩展函数(例如在Javascript中)编写。