Обновить элементы, используя LINQ to XML? - PullRequest
0 голосов
/ 19 октября 2011

У меня есть следующий XML, но мне трудно понять, как обновить элементы напрямую, используя LINQ to XML:

XElement settings = XElement.Parse (
@"<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' 
                  xmlns:xsd='http://www.w3.org/2001/XMLSchema'
                  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'    
                  xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'
                  xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' 
                  xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand='1'> 
    <wsse:UsernameToken wsu:Id='UsernameToken-72135529'> 
        <wsse:Username>{USERNAME}</wsse:Username> 
        <wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'>{PASSWORD}</wsse:Password> 
    </wsse:UsernameToken> 
 </wsse:Security> 
    <wsa:MessageID>{MESSAGEID}</wsa:MessageID> 
    <wsa:To>{TO}</wsa:To> 
    <wsa:Action>{ACTION}</wsa:Action> 
    <wsa:From> 
    <wsa:Address>{ADDRESS}</wsa:Address> 
</wsa:From> 
   </soapenv:Header>
   <soapenv:Body>
{BODY}
  </soapenv:Body>
</soapenv:Envelope>");

Например, в приведенном выше примере я хочу получить доступ к каждому элементу со значением плашдолдера {} и обновить текст. Правильно ли работает XElement.Parse() в этом сценарии? Я, скорее всего, собираюсь загрузить его и сначала XDocument, а затем обновить элементы. Кроме того, как я могу обновить атрибуты, такие как атрибут Type в Password?

Попытка получить имя пользователя, но он говорит, что это исключение InvalidOperationException.

XNamespace xmlns = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace wsa = "http://schemas.xmlsoap.org/ws/2004/08/addressing";
XNamespace wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
XNamespace wsu = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";

var textElement = settings.Elements(xmlns + "Envelope").
                           Elements(xmlns + "Header").
                           Elements(wsse + "Security").
                           Elements(wsse + "UsernameToken").
                           Elements(wsse + "Username").Single();

Кроме того, только я или использование XPath кажется более простым, если я знаю точное положение элементов и, например, если я хочу обновить или удалить xmlns: wsa, как это будет достигнуто?

Ответы [ 2 ]

1 голос
/ 19 октября 2011

Это будет сделано

var elements = settings.DescendantNodes().OfType<XText>().Where(p => p.Value.StartsWith("{") && p.Value.EndsWith("}"));

foreach (var node in elements)
{
    // This is an example of manipulation. It will simply remove the {}
    node.Value = node.Value.Substring(1, node.Value.Length - 2);
}

Вы можете переместить условие Where непосредственно в цикл for, например

var elements = settings.DescendantNodes().OfType<XText>();

foreach (var node in elements.Where(p => p.Value.StartsWith("{") && p.Value.EndsWith("}")))
{
    // This is an example of manipulation. It will simply remove the {}
    node.Value = node.Value.Substring(1, node.Value.Length - 2);
}

Инструкция по поиску XText узлов из Значение XElement в C #

Обратите внимание, что вам необходимо добавить отсутствующие пространства имен:

xmlns:wsse='something' xmlns:wsa='somethingelse' xmlns:wsu='somethingelseelse'

или XElement.Parse сломается;

Если вы хотите обновить один элемент, имя которого вам известно:

XNamespace wsa = "somethingelse"; // Here you must put the namespace!

var textElement = settings.Descendants(wsa + "MessageID").Single(); // If there is only one Message ID to change (0 or > 1 MessageID will make Single throw), .First() if you are only interested in the first one
textElement.Value = "MessageID"; // Changed!

или

var textElements = settings.Descendants(wsa + "MessageID") // If there are multipleMessage ID to change

foreach (var textElement in textElements)
{
    textElement.Value = "MessageID"; // Changed!
}

Имейте в виду, что эти варианты будут изменять первый / все wsa: MessageID, игнорируя их положение.

или, если вы знаете точный «путь» к вашему узлу, используйте что-то вроде

var textElements = settings.Elements(name1).Elements(name2)...

, а затем используйте Single(), .First() илиforeach

Небольшой пример кода:

XElement settings = XElement.Parse(
@"<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing' xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>
    <soapenv:Header>
        <wsse:Security soapenv:mustUnderstand='1'> 
            <wsse:UsernameToken wsu:Id='UsernameToken-72135529'> 
                <wsse:Username>{USERNAME}</wsse:Username> 
                <wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'>{PASSWORD}</wsse:Password> 
            </wsse:UsernameToken> 
        </wsse:Security> 
        <wsa:MessageID>{MESSAGEID}</wsa:MessageID> 
        <wsa:To>{TO}</wsa:To> 
        <wsa:Action>{ACTION}</wsa:Action> 
        <wsa:From> 
            <wsa:Address>{ADDRESS}</wsa:Address> 
        </wsa:From> 
    </soapenv:Header>
    <soapenv:Body>
        {BODY}
    </soapenv:Body>
</soapenv:Envelope>");


var soapenv = settings.GetNamespaceOfPrefix("soapenv");
var wsa = settings.GetNamespaceOfPrefix("wsa");
var wsse = settings.GetNamespaceOfPrefix("wsse");
var wsu = settings.GetNamespaceOfPrefix("wsu");

XElement username = settings.Elements(soapenv + "Header").Elements(wsse + "Security").Elements(wsse + "UsernameToken").Elements(wsse + "Username").Single();
Console.WriteLine(username);
username.Value = "NewValue";
Console.WriteLine(username);
0 голосов
/ 19 октября 2011

Я также узнал, что я могу просто использовать локальные имена без необходимости объявлять пространства имен, выполнив следующее:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...