1. ホーム
  2. c#

[解決済み] LINQによるXDocumentの検索は、名前空間が分からなくても可能です。

2023-06-25 10:25:09

質問

名前空間を知らずに XDocument を検索する方法はありますか? 私は、すべての SOAP リクエストを記録し、機密データを暗号化するプロセスを持っています。 私は、名前に基づいて任意の要素を見つけたい。 例えば、名前がCreditCardであるすべての要素を私に与えるようなものです。私は名前空間が何であるかを気にしない。

私の問題はLINQとxmlの名前空間を要求することにあるようです。

私はXMLから値を取得する他のプロセスを持っていますが、私はこれらの他のプロセスのための名前空間を知っています。

XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml");
XNamespace xNamespace = "http://CompanyName.AppName.Service.Contracts";

var elements = xDocument.Root
                        .DescendantsAndSelf()
                        .Elements()
                        .Where(d => d.Name == xNamespace + "CreditCardNumber");

名前空間を知らなくてもxmlを検索できる機能がどうしても欲しい、こんな感じです。

XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml");
var elements = xDocument.Root
                        .DescendantsAndSelf()
                        .Elements()
                        .Where(d => d.Name == "CreditCardNumber")

コンパイル時にあらかじめ名前空間を知らないので、これではうまくいきません。

どうすればいいのでしょうか?

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Request xmlns="http://CompanyName.AppName.Service.ContractA">
        <Person>
            <CreditCardNumber>83838</CreditCardNumber>
            <FirstName>Tom</FirstName>
            <LastName>Jackson</LastName>
        </Person>
        <Person>
            <CreditCardNumber>789875</CreditCardNumber>
            <FirstName>Chris</FirstName>
            <LastName>Smith</LastName>
        </Person>
        ...

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Request xmlns="http://CompanyName.AppName.Service.ContractsB">
        <Transaction>
            <CreditCardNumber>83838</CreditCardNumber>
            <TransactionID>64588</FirstName>
        </Transaction>      
        ...

どのように解決するのですか?

Adam がコメントで正確に述べているように、XName は文字列に変換可能ですが、その文字列は、名前空間がある場合はそれを必要とします。これが、.Name と文字列の比較に失敗する理由、または XLinq メソッドのパラメーターとして "Person" を渡して名前でフィルターをかけることができない理由です。

XNameはプレフィックス(Namespace)とLocalNameから構成される。ローカル名は、名前空間を無視する場合にクエリするものです。

アダムさん、ありがとうございます。)

.Descendants()メソッドのパラメータにノードのNameを入れることはできませんが、その方法でクエリすることは可能です :

var doc= XElement.Parse(
@"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
  <Request xmlns=""http://CompanyName.AppName.Service.ContractA"">
    <Person>
        <CreditCardNumber>83838</CreditCardNumber>
        <FirstName>Tom</FirstName>
        <LastName>Jackson</LastName>
    </Person>
    <Person>
        <CreditCardNumber>789875</CreditCardNumber>
        <FirstName>Chris</FirstName>
        <LastName>Smith</LastName>
    </Person>
   </Request>
   </s:Body>
</s:Envelope>");

EDIT : 私のテストからの悪いコピー/ペースト :)

var persons = from p in doc.Descendants()
              where p.Name.LocalName == "Person"
              select p;

foreach (var p in persons)
{
    Console.WriteLine(p);
}

これでうまくいく...