更改嵌套节点的值
Posted
技术标签:
【中文标题】更改嵌套节点的值【英文标题】:Change Value of nested node 【发布时间】:2021-11-30 13:54:03 【问题描述】:这似乎是一个简单的问题,但我似乎无法着手制定可行的解决方案。最终目标是更改下面突出显示的ConstantValue
元素的值。我的策略是找到Component
节点并从那里向下钻取。问题是不断返回一个空值,我不知道为什么。下面是我正在使用的代码,我正在使用的 xml。任何提示都会很棒。
XDocument xmlDoc = XDocument.Parse(str);
var items = xmlDoc.Descendants("Component")
.Where(x => x.Attribute("Name").Value == "axesInterface")
.FirstOrDefault();
<?xml version="1.0" encoding="utf-8"?>
<Document>
<Engineering version="V17" />
<DocumentInfo>
</DocumentInfo>
<SW.Blocks.FB ID="0">
<AttributeList>
<Interface><Sections></Sections></Interface>
<MemoryLayout>Optimized</MemoryLayout>
<MemoryReserve>100</MemoryReserve>
<Name>EM00_CM01_Warp1</Name>
<Number>31650</Number>
<ProgrammingLanguage>LAD</ProgrammingLanguage>
<SetENOAutomatically>false</SetENOAutomatically>
</AttributeList>
<ObjectList>
<SW.Blocks.CompileUnit ID="4" CompositionName="CompileUnits">
<AttributeList>
<NetworkSource>
<FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
<Parts>
<Access Scope="GlobalVariable" UId="27">
<Symbol>
<Component Name="HMIAxisCtrl_Interface" />
<Component Name="axesInterface" AccessModifier="Array">
<Access Scope="LiteralConstant">
<Constant>
<ConstantType>DInt</ConstantType>
<ConstantValue>0</ConstantValue>
</Constant>
</Access>
</Component>
</Symbol>
</Access>
</Parts>
</FlgNet>
</NetworkSource>
</AttributeList>
</SW.Blocks.CompileUnit>
</ObjectList>
</SW.Blocks.FB>
</Document>
【问题讨论】:
如果您包含格式良好的 XML 来说明您正在尝试做什么(作为文本,格式化为 代码我>)。这样,人们就可以获取您的 XML 并使用它。包括代码(XML 不是完全代码,但它足够接近)作为文本总是比作为图片更好 您需要像@Charlieface 在他的回答中那样处理 FlgNet 元素上的命名空间 【参考方案1】:您可以使用 XQuery 获取正确的节点:
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
//
var nm = new XmlNamespaceManager(new NameTable());
nm.AddNamespace("sm", "http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4");
var node = xdoc.XPathSelectElement(@"//sm:Access[@Scope=""LiteralConstant""]/sm:Constant/sm:ConstantValue", nm);
node.Value = "Something Else";
dotnetfiddle
对于多个节点,将XPathSelectElement
更改为XPathSelectElements
【讨论】:
谢谢。这是一个不错的选择。【参考方案2】:在您的 XML 示例中,您可以使用这段代码在任意深度简单地获取指定节点:
XDocument xmlDoc = XDocument.Parse(str);
XElement node = xmlDoc.Descendants().FirstOrDefault(x => x.Name.LocalName == "ConstantValue");
node.Value = "New value";
xmlDoc.Save(somewhere);
如果可能有多个节点名称为 "ConstantValue"
- 那么只需将 FirstOrDefault
替换为 Where
并使用按名称过滤的 IEnumerable<XElement>
。
为什么x.Name == "ConstantValue"
找不到它:
编辑:添加示例。
// That's your parent node
var componentNode = xmlDoc.Descendants()
.Where(x => x.Name.LocalName == "Component"
&& (string)x.Attribute("Name") == "axesInterface");
// Get first ConstantValue node from parent Component node
var constantValueNode = componentNode.Descendants()
.FirstOrDefault(x => x.Name.LocalName == "ConstantValue");
// or get all ConstantValue nodes from parent Component node
var constantValueNodes = componentNode.Descendants()
.Where(x => x.Name.LocalName == "ConstantValue");
if (constantValueNode is XElement)
constantValueNode.Value = "New value";
您可以通过指定级别创建扩展方法来获取父节点:
public static class Extensions
public static XElement GetParentNode(this XElement element, int parentLevel)
XElement node = element.Parent;
for (int i = 0; i < parentLevel; i++)
node = node.Parent;
return node;
在您的示例中,var parent = constantValueNode.GetParentNode(2);
将返回组件节点(具有属性 Name="axesInterface"
)。 var parent = constantValueNode.GetParentNode(12);
将返回根“文档”节点。
【讨论】:
很好的解决方案。问题是我给出的代码是一个更简单的版本,以保持简短。有很多ConstantValue
节点。是否可以指定一个父节点......甚至更好的是 parent 的父节点。例如,我可以看到属于特定组件的ConstantValue
(在 xml 示例中向上 2 级)?
@mrsargent,请检查我编辑了答案并在最后添加了一些代码。您可以通过Descendants()
和x.Name.LocalName = "YouNodeName"
获得any 深度的any 节点。或者我不明白你的要求:/以上是关于更改嵌套节点的值的主要内容,如果未能解决你的问题,请参考以下文章