Есть ли способ выполнить поиск в 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>
...
c#
linq-to-xml
Майк Барлоу - BarDev
источник
источник
Ответы:
Как уточняет Адам в комментарии, XName можно преобразовать в строку, но для этой строки требуется пространство имен, если оно есть. Вот почему сравнение .Name со строкой не удается или почему вы не можете передать «Person» в качестве параметра методу XLinq для фильтрации по их имени.
XName состоит из префикса (пространства имен) и LocalName. Локальное имя - это то, что вы хотите запросить, если вы игнорируете пространства имен.
Спасибо, Адам :)
Вы не можете указать имя узла в качестве параметра метода .Descendants (), но можете запросить таким образом:
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>");
РЕДАКТИРОВАТЬ: плохая копия / прошлое из моего теста :)
var persons = from p in doc.Descendants() where p.Name.LocalName == "Person" select p; foreach (var p in persons) { Console.WriteLine(p); }
Это подходит для меня...
источник
Вы можете взять пространство имен из корневого элемента:
XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); var ns = xDocument.Root.Name.Namespace;
Теперь вы можете легко получить все желаемые элементы с помощью оператора плюс:
root.Elements(ns + "CreditCardNumber")
источник
LINQ
операций.Думаю, я нашел то, что искал. В следующем коде вы можете видеть, что я выполняю оценку
Element.Name.LocalName == "CreditCardNumber"
. В моих тестах это сработало. Я не уверен, что это лучшая практика, но я собираюсь ее использовать.XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); var elements = xDocument.Root.DescendantsAndSelf().Elements().Where(d => d.Name.LocalName == "CreditCardNumber");
Теперь у меня есть элементы, в которых я могу зашифровать значения.
Если у кого-то есть лучшее решение, предоставьте его. Благодарю.
источник
Если ваши XML-документы всегда определяют пространство имен в одном и том же узле (
Request
узел в двух приведенных примерах), вы можете определить его, сделав запрос и посмотрев, какое пространство имен имеет результат: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; }
источник
Есть пара ответов с удаленными методами расширения. Не знаю почему. Вот моя версия, которая подходит для моих нужд.
public static class XElementExtensions { public static XElement ElementByLocalName(this XElement element, string localName) { return element.Descendants().FirstOrDefault(e => e.Name.LocalName == localName && !e.IsEmpty); } }
Это
IsEmpty
отфильтровать узлы сx:nil="true"
Могут быть дополнительные тонкости - поэтому используйте с осторожностью.
источник
Просто используйте метод потомков:
XDocument doc = XDocument.Load(filename); String[] creditCards = (from creditCardNode in doc.Root.Descendents("CreditCardNumber") select creditCardNode.Value).ToArray<string>();
источник