Gibt es eine Möglichkeit, ein XDocument zu durchsuchen, ohne den Namespace zu kennen? Ich habe einen Prozess, der alle SOAP-Anforderungen protokolliert und die vertraulichen Daten verschlüsselt. Ich möchte alle Elemente finden, die auf dem Namen basieren. Geben Sie mir alle Elemente, bei denen der Name CreditCard lautet. Es ist mir egal, was der Namespace ist.
Mein Problem scheint mit LINQ zu sein und einen XML-Namespace zu erfordern.
Ich habe andere Prozesse, die Werte aus XML abrufen, aber ich kenne den Namespace für diese anderen Prozesse.
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");
Ich möchte wirklich die Möglichkeit haben, XML zu durchsuchen, ohne etwas über Namespaces zu wissen.
XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml");
var elements = xDocument.Root
.DescendantsAndSelf()
.Elements()
.Where(d => d.Name == "CreditCardNumber")
Dies funktioniert nicht, da ich den Namespace zur Kompilierungszeit nicht vorher kenne.
Wie kann das gemacht werden?
<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>
...
quelle
Antworten:
Wie Adam im Kommentar präzisiert, kann XName in eine Zeichenfolge konvertiert werden, für diese Zeichenfolge ist jedoch der Namespace erforderlich, wenn es einen gibt. Aus diesem Grund schlägt der Vergleich von .Name mit einer Zeichenfolge fehl oder Sie können "Person" nicht als Parameter an die XLinq-Methode übergeben, um nach ihrem Namen zu filtern.
XName besteht aus einem Präfix (dem Namespace) und einem LocalName. Der lokale Name ist das, wonach Sie abfragen möchten, wenn Sie Namespaces ignorieren.
Danke Adam :)
Sie können den Namen des Knotens nicht als Parameter der .Descendants () -Methode angeben, aber Sie können auf folgende Weise abfragen:
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: schlechte Kopie / Vergangenheit von meinem Test :)
var persons = from p in doc.Descendants() where p.Name.LocalName == "Person" select p; foreach (var p in persons) { Console.WriteLine(p); }
Das ist für mich in Ordnung...
quelle
Sie können den Namespace aus dem Root-Element übernehmen:
XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); var ns = xDocument.Root.Name.Namespace;
Jetzt können Sie alle gewünschten Elemente einfach mit dem Plus-Operator abrufen:
root.Elements(ns + "CreditCardNumber")
quelle
LINQ
Operationen ausführen können.Ich glaube, ich habe gefunden, wonach ich gesucht habe. Sie können im folgenden Code sehen, dass ich die Auswertung mache
Element.Name.LocalName == "CreditCardNumber"
. Dies schien in meinen Tests zu funktionieren. Ich bin mir nicht sicher, ob es eine bewährte Methode ist, aber ich werde sie verwenden.XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); var elements = xDocument.Root.DescendantsAndSelf().Elements().Where(d => d.Name.LocalName == "CreditCardNumber");
Jetzt habe ich Elemente, mit denen ich die Werte verschlüsseln kann.
Wenn jemand eine bessere Lösung hat, geben Sie diese bitte an. Vielen Dank.
quelle
Wenn Ihre XML-Dokumente immer den Namespace im selben Knoten definieren (
Request
Knoten in den beiden angegebenen Beispielen), können Sie ihn ermitteln, indem Sie eine Abfrage durchführen und sehen, welchen Namespace das Ergebnis hat:XDocument xDoc = XDocument.Load("filename.xml"); //Initial query to get namespace: var reqNodes = from el in xDoc.Root.Descendants() where el.Name.LocalName == "Request" select el; foreach(var reqNode in reqNodes) { XNamespace xns = reqNode.Name.Namespace; //Queries making use of namespace: var person = from el in reqNode.Elements(xns + "Person") select el; }
quelle
Es gibt einige Antworten mit Erweiterungsmethoden, die gelöscht wurden. Nicht sicher warum. Hier ist meine Version, die für meine Bedürfnisse funktioniert.
public static class XElementExtensions { public static XElement ElementByLocalName(this XElement element, string localName) { return element.Descendants().FirstOrDefault(e => e.Name.LocalName == localName && !e.IsEmpty); } }
Das
IsEmpty
ist, um Knoten mit herauszufilternx:nil="true"
Es kann zusätzliche Feinheiten geben - verwenden Sie diese daher mit Vorsicht.
quelle
Verwenden Sie einfach die Descendents-Methode:
XDocument doc = XDocument.Load(filename); String[] creditCards = (from creditCardNode in doc.Root.Descendents("CreditCardNumber") select creditCardNode.Value).ToArray<string>();
quelle