使用C#Regular表达式替换XML元素内容

时间:2009-01-15 20:40:08

标签: c# .net xml regex parsing

我正在编写一些处理日志记录xml数据的代码,我希望能够替换文档中某些元素(例如密码)的内容。我宁愿不序列化和解析文档,因为我的代码将处理各种模式。

示例输入文档:

doc#1:

   <user>
       <userid>jsmith</userid>
       <password>myPword</password>
    </user>

doc#2:

<secinfo>
       <ns:username>jsmith</ns:username>
       <ns:password>myPword</ns:password>
 </secinfo>

我希望我的输出是:

输出文档#1:

<user>
       <userid>jsmith</userid>
       <password>XXXXX</password>
 </user>

输出文档#2:

<secinfo>
       <ns:username>jsmith</ns:username>
       <ns:password>XXXXX</ns:password>
 </secinfo>

由于我将要处理的文档可能有各种模式,我希望能找到一个很好的通用正则表达式解决方案,它可以找到包含密码的元素并相应地屏蔽内容。

我可以使用正则表达式和C#来解决这个问题,还是有更有效的方法?

7 个答案:

答案 0 :(得分:21)

使用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="//password">
        <xsl:copy>
            <xsl:text>XXXXX</xsl:text>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

只要正确处理命名空间,这将适用于两个输入。

编辑:澄清“正确处理命名空间”的含义

确保具有ns名称前缀的源文档具有为文档定义的命名空间,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<secinfo xmlns:ns="urn:foo">
    <ns:username>jsmith</ns:username>
    <ns:password>XXXXX</ns:password>
</secinfo>

答案 1 :(得分:8)

我说你最好用.NET XmlDocument对象解析内容并使用XPath查找密码元素,然后更改它们的innerXML属性。它具有更正确的优点(因为XML首先不是常规的),并且它在概念上很容易理解。

答案 2 :(得分:8)

根据使用没有适当解析器来尝试解析和/或修改XML的系统的经验,让我说:不要做它。使用XML解析器(此处还有其他答案可以快速轻松地完成此操作)。

使用非xml方法来解析和/或修改XML流将总是会让您在将来的某个时刻感到痛苦。我知道,因为我感到痛苦。

我知道如果您使用正则表达式解决方案,它似乎会更快 - 运行时/更简单 - 代码/更容易理解/无论如何。但是你以后只会让别人的生活变得悲惨。

答案 3 :(得分:1)

如果您对自己想要匹配的内容有足够的了解,可以使用正则表达式。例如,如果您正在查找其中没有内部标记的任何标记“密码”,则此正则表达式将起作用:

(<([^>]*?password[^>]*?)>)([^<]*?)(<\/\2>)

您也可以在zowat的答案中使用相同的C#替换语句,但对于替换字符串,您可能希望使用“$ 1XXXXX $ 4”。

答案 4 :(得分:1)

正则表达式对此是错误的方法,我看到它在你最不期望它时会出现如此严重的错误。

无论如何,XDocument更有趣:

XDocument doc = XDocument.Parse(@"
            <user>
                <userid>jsmith</userid>
                <password>password</password>
            </user>");

doc.Element("user").Element("password").Value = "XXXX";

// Temp namespace just for the purposes of the example -
XDocument doc2 = XDocument.Parse(@"
            <secinfo xmlns:ns='http://tempuru.org/users'>
                <ns:userid>jsmith</ns:userid>
                <ns:password>password</ns:password>
            </secinfo>");

doc2.Element("secinfo").Element("{http://tempuru.org/users}password").Value = "XXXXX";

答案 5 :(得分:1)

这是我在使用XMLDocument时提出的内容,它可能不像XSLT那样灵活,但应该足够通用以处理各种文档:

            //input is a String with some valid XML
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(input);
            XmlNodeList nodeList = doc.SelectNodes("//*");

            foreach (XmlNode node in nodeList)
            {
                if (node.Name.ToUpper().Contains("PASSWORD"))
                {
                    node.InnerText = "XXXX";
                }
                else if (node.Attributes.Count > 0)
                {
                    foreach (XmlAttribute a in node.Attributes)
                    {
                        if (a.LocalName.ToUpper().Contains("PASSWORD"))
                        {
                            a.InnerText = "XXXXX";
                        }
                    }
                }    
            }

答案 6 :(得分:1)

XSLT存在的主要原因是能够转换XML结构,这意味着XSLT是一种样式表,可用于改变元素的顺序和更改元素的内容。因此,这是一个典型的情况,强烈建议使用XSLT而不是解析,就像Andrew Hare在之前的帖子中所说的那样。