18

アプリケーションから非常に大きな XML 出力があります。それを自分のプログラムで処理してから、元のプログラムにフィードバックする必要があります。この XML には、置換する必要がある部分があります。興味深い部分は次のようになります。

<sys:customtag sys:sid="1" sys:type="Processtart" />
    <sys:tag>value</sys:tag>
    here are some other tags
    <sys:tag>value</sys.tag>
<sys:customtag sys:sid="1" sys:type="Procesend" />

ドキュメントには、このようないくつかの部分が含まれています。

これらのタグを変更できるようにするには、これらのタグ内のすべての XML 部分を取得する必要があります。これらの部分を取得する正規表現を作成しましたが、機能しません。

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(@"output.xml");
Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>", RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant);
MatchCollection matches = regExp.Matches(xmlDoc.InnerXml);

全体を 1 行に残して、複数行オプションなしでこの正規表現を呼び出すと、すべての出現箇所が検出されます。ファイルをそのままにして、複数行オプションを設定すると、機能しません。何が問題なのですか、何を変更すればよいですか? または、正規表現なしでこれらのタグ間の XML 部分を取得する簡単な方法はありますか?

4

4 に答える 4

49

使用するオプションは(srcRegexOptions.Singleline )の代わりだと思います。(.) が改行に一致することを許可することは、あなたの場合にうまくいくはずです。RegexOptions.Multiline

...ドットが改行にも一致するモードは「単一行モード」と呼ばれます。この用語は「複数行モード」と混同しやすいため、これは少し残念です。複数行モードはアンカーにのみ影響し、単一行モードはドットにのみ影響します... .NET フレームワークの正規表現クラスを使用する場合は、RegexOptions.Singleline を Regex.Match("string "、"regex"、RegexOptions.Singleline)。

于 2008-11-14T07:48:13.343 に答える
6

正規表現文字 "." MultiLineオプションが設定されていても、改行には一致しません。代わりに、[\s\S]またはその他の組み合わせを使用する必要があります。

このMultiLineオプションは、^ (文字列の先頭ではなく行頭) と $ (文字列の末尾ではなく行末) の動作のみを変更します。

ところで:確かに、正規表現は HTML をスキャンする正しい方法ではありません...

于 2008-11-14T12:51:26.460 に答える
4

RegExp は xml の貧弱なツールです...それを XDocument / XmlDocument にロードして xpath を使用することはできませんか? 行いたい変更を明確にすれば、空白を埋めることができると思います...この場合、名前空間がおそらく複雑にする主なものなので、XmlNamespaceManager.

これは、単なる正規表現よりも複雑な例ですが、xml のニュアンスにうまく対処できると思います。

    string xml = @"<foo xmlns:sys=""foobar""><bar/><bar><sys:customtag sys:sid=""1"" sys:type=""Processtart"" />
<sys:tag>value</sys:tag>
here are some other tags
<sys:tag>value</sys:tag>
<sys:customtag sys:sid=""1"" sys:type=""Procesend"" /></bar><bar/></foo>";

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml);
    XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
    mgr.AddNamespace("sys", "foobar");
    var matches = doc.SelectNodes("//sys:customtag[@sys:type='Processtart']", mgr);
    foreach (XmlElement start in matches)
    {
        XmlElement end = (XmlElement) start.SelectSingleNode("following-sibling::sys:customtag[@sys:type='Procesend'][1]",mgr);
        XmlNode node = start.NextSibling;
        while (node != null && node != end)
        {
            Console.WriteLine(node.OuterXml);

            node = node.NextSibling;
        }
    }
于 2008-11-14T07:48:45.930 に答える
4

それでも問題が解決しない場合は、OR ではなく AND を RegexOptions で使用している可能性があります。

このコードは間違っており、コンストラクターの 2 番目のパラメーターとして 0 を渡します。

Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>",
RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant);

このコードは正しいです (複数の RegexOptions フラグを使用する限り):

Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>",
RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);
于 2008-12-02T19:18:34.940 に答える