Использование регулярного выражения C # для замены содержимого элемента XML - PullRequest
4 голосов
/ 15 января 2009

Я пишу некоторый код, который обрабатывает регистрацию данных XML, и я хотел бы иметь возможность заменить содержимое определенных элементов (например, паролей) в документе. Я бы предпочел не сериализовать и не анализировать документ, так как мой код будет обрабатывать различные схемы.

Образцы входных документов:

Документ № 1:

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

документ № 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 ]

21 голосов
/ 15 января 2009

Эту проблему лучше всего решить с помощью 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>
8 голосов
/ 16 января 2009

Из опыта работы с системами, которые пытаются анализировать и / или изменять XML без надлежащих анализаторов, позвольте мне сказать: НЕ ДЕЛАЙТЕ ЭТОГО . Используйте синтаксический анализатор XML (здесь есть другие ответы, в которых есть способы сделать это быстро и легко).

Использование не-xml методов для анализа и / или изменения потока XML ВСЕГДА приведет к боли в будущем. Я знаю, потому что я чувствовал эту боль.

Я знаю, что кажется, что было бы быстрее во время выполнения / проще для кода / легче для понимания / чем угодно, если бы вы использовали решение регулярных выражений. Но потом ты просто сделаешь чью-то жизнь несчастной.

8 голосов
/ 15 января 2009

Я бы сказал, что лучше разбирать содержимое с помощью объекта .NET XmlDocument и находить элементы пароля с помощью XPath, а затем изменять их свойства innerXML. Его преимущество в том, что он более корректен (поскольку XML, во-первых, не является регулярным) и концептуально прост для понимания.

1 голос
/ 10 ноября 2009

Основная причина существования XSLT - возможность преобразовывать XML-структуры, это означает, что XSLT - это тип таблицы стилей, который можно использовать для изменения порядка элементов или изменения содержимого элементов. Поэтому это типичная ситуация, когда настоятельно рекомендуется использовать XSLT вместо анализа, как сказал Эндрю Хэйр в предыдущем посте.

1 голос
/ 16 января 2009

Вот то, что я придумал, когда пришел с 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";
                        }
                    }
                }    
            }
1 голос
/ 16 января 2009

Регулярное выражение - неправильный подход для этого, я видел, что все идет так плохо, когда вы меньше всего этого ожидаете.

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";
1 голос
/ 16 января 2009

Вы можете использовать регулярные выражения, если знаете достаточно о том, что вы пытаетесь сопоставить. Например, если вы ищете какой-либо тег, в котором есть слово «пароль» без внутренних тегов, это выражение регулярного выражения будет работать:

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

Вы также можете использовать тот же оператор C # replace в ответе zowat, но вместо строки замены вы захотите использовать "$ 1XXXXX $ 4".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...