使用 LINQ to XML 更新元素?

发布于 2024-12-10 15:17:57 字数 2449 浏览 1 评论 0 原文

我有以下 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 中,然后更新元素。另外,如何更新属性,例如 Password 上的 Type 属性?

尝试获取用户名,但它说这是一个 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();

另外,如果我知道元素的确切位置,或者如果我想更新或删除 xmlns:wsa,那么使用 XPath 是否看起来更简单,这将如何实现?

I have the following XML, but I am having a hard time figuring out how to update the elements directly using 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>");

For example, in the above, I want to access each element that has placholder value {} and update the text. Is doing XElement.Parse() correct in this scenario? I am most likely going to load it into and XDocument first and then update the elements. Also, how could I update attributes, like the Type attribute on Password?

Trying to get to Username, but it says it is an 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();

Also, is it just me or does using XPath seem simpler if I know the exact position of the elements and if I wanted to update or remove xmlns:wsa for example, how would that be achieved?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

囍孤女 2024-12-17 15:17:57

这样就可以了。

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);
}

您可以直接在 for 循环中移动 Where 条件,例如

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 节点的指令来自 C# 中的 XElement 值

请注意,您需要添加缺少的命名空间:

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< /code>

一个小示例代码:

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);

This will do it

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);
}

You could move the Where condition directly in the for cycle, like

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);
}

The instruction for finding XText nodes are from XElement value in C#

Note that you'll need to add the missing namespaces:

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

or the XElement.Parse will break;

If you want to update a single element of which you know the name:

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!

or

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

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

Be aware that these variants will change the first/all the wsa:MessageID, ignoring their position.

or if you know the exact "path" to your node, use something like

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

and then use the Single(), the .First() or the foreach

A small sample code:

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);
月下伊人醉 2024-12-17 15:17:57

我还发现我可以只使用本地名称,而不必通过执行以下操作来声明名称空间:

XElement user = settings.Descendants().Where(o => o.Name.LocalName == "Username").Single();

I also found out that I can just use the local names without having to declare the namespaces by doing the following:

XElement user = settings.Descendants().Where(o => o.Name.LocalName == "Username").Single();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文