给出一些输入数据:
<somexml>
<User Name="MrFlibble">
<Option Name="Pass">SomeSaltedPassword</Option>
<Option Name="Salt">Salt</Option>
<tag1></tag1>
<Permissions>
<Permission Dir="E:"></Permission>
</Permissions>
</User>
<User Name="MrFlobble">
<Option Name="Pass">SomeOtherSaltedPassword</Option>
<Option Name="Salt">Salt</Option>
<tag1></tag1>
<Permissions>
<Permission Dir="C:"></Permission>
</Permissions>
</User>
</somexml>
我想用C:
和MrFlibble
替换用户区域(在本例中为Jon
)中没有SomeSaltedPassword
权限的第一个用户与MyNewSaltedPassword
一起使用.net框架正则表达式得出以下结果:
<somexml>
<User Name="Jon">
<Option Name="Pass">MyNewSaltedPassword</Option>
<Option Name="Salt">Salt</Option>
<tag1></tag1>
<Permissions>
<Permission Dir="E:"></Permission>
</Permissions>
</User>
<User Name="MrFlobble">
<Option Name="Pass">SomeOtherSaltedPassword</Option>
<Option Name="Salt">Salt</Option>
<tag1></tag1>
<Permissions>
<Permission Dir="C:"></Permission>
</Permissions>
</User>
</somexml>
我认为像这样的正则表达式将捕获用户并将我要替换的部分分组:
<User Name="(.*)">.*<Option Name="Pass">(.*)<\/Option>.*<Option Name="Salt">(.*)<\/Option>.*<\/User>
...但是我正在努力查看如何在保留其他文本的同时替换这三个组。 The docs似乎都建议用特定的新文本代替对原始文本的修改,而不是用多个特定命名的组。
是否有执行此操作的标准方法?还是我吠叫了错误的树?
答案 0 :(得分:1)
在任何情况下都不要尝试使用正则表达式解析XML,除非您希望调用rite 666。 Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn。
使用XML解析库,请参见this page,了解某些实现方法。
答案 1 :(得分:1)
使用正则表达式很难做到这一点,因为您需要按条件替换。
在你写的,它是格式良好的XML注释。因此,我敢使用XML解析器提供了解决方案。
将对System.Xml.Linq库的引用添加到项目中。 打开以下命名空间
using namespace System;
using namespace System::IO;
using namespace System::Xml::Linq;
代码非常简单明了
//auto xml = XElement::Parse(input); // input - string containing your xml
auto xml = XElement::Load(L"test.xml");
for each (auto user in xml->Elements(L"User"))
{
if (user->Element(L"Permissions")->Element(L"Permission")->Attribute(L"Dir")->Value != L"C:")
{
user->Attribute(L"Name")->Value = L"Jon";
for each(auto option in user->Elements(L"Option"))
{
if (option->Attribute(L"Name")->Value == L"Pass")
{
option->Value = L"MyNewSaltedPassword";
}
}
}
}
Console::WriteLine(xml);
//xml->Save(L"result.xml");
答案 2 :(得分:1)
带有正则表达式的选项。该表达式本身看起来晦涩难懂,因此很难维护。因此,最好将该方法与xml解析器一起使用。
using namespace System;
using namespace System::IO;
using namespace System::Text::RegularExpressions;
MatchEvaluator方法:
String^ Evaluate(Match^ m)
{
if (m->Groups[L"dir"]->Value != L"C:")
return L"Jon" + m->Groups[L"mid1"] + L"MyNewSaltedPassword" + m->Groups[L"mid2"] + m->Groups[L"dir"];
else
return m->Groups[L"name"]->Value + m->Groups[L"mid1"] + m->Groups[L"pass"] + m->Groups[L"mid2"] + m->Groups[L"dir"];
}
代码:
auto input = File::ReadAllText(L"test.xml");
auto pattern = gcnew String(R"(
(?<= <User \s Name = " )
(?'name' .+? )
(?= "> )
(?'mid1' .+? )
(?<= <Option \s Name = "Pass"> )
(?'pass' .+? )
(?= </Option> )
(?'mid2' .+? )
(?<= <Permission \s Dir = " )
(?'dir' .+? )
(?= "> )
)");
auto options = RegexOptions::IgnorePatternWhitespace | RegexOptions::Singleline;
auto evaluator = gcnew MatchEvaluator(Evaluate);
auto result = Regex::Replace(input, pattern, evaluator, options);
Console::WriteLine(result);