【发布时间】:2017-03-10 10:18:06
【问题描述】:
这是我在这里的第一篇文章。感谢 mil 的陪伴,如果我在第一次尝试中犯了错误或造成误解,我们深表歉意。我的难题如下: 我写了一个小脚本来更新一些第三方软件组件,这需要更改一个具有以下结构的 XML 文件:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>xxx</ProjectGuid>
<OutputType>xxx</OutputType>
<StartupObject>xxx</StartupObject>
<RootNamespace>xxx</RootNamespace>
<AssemblyName>xxx</AssemblyName>
<FileAlignment>xxx</FileAlignment>
<MyType>WindowsFormsWithCustomSubMain</MyType>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<SccProjectName>xxx</SccProjectName>
<SccLocalPath>xxx</SccLocalPath>
<SccAuxPath>xxx</SccAuxPath>
<SccProvider>xxx</SccProvider>
</PropertyGroup>
<PropertyGroup>
...
<ItemGroup>
<Reference Include="someString, Version=123, Culture=neutral, PublicKeyToken=ab1, processorArchitecture=xxx">
<SpecificVersion>False</SpecificVersion>
<Private>True</Private>
</Reference>
有问题的函数从属性 include 中获取子字符串,理想情况下应该将其添加到新创建的 XML 元素中(即<HintPath>xyz</HintPath>)。一旦我解决了命名空间问题(感谢 StackOverflow),就可以选择属性并获取字符串。但是,当我要使用 AppendChild 添加 HintPath 元素时,我收到一条错误消息,指出该对象未正确引用。我尝试使用 LINQ 来解决问题,但无法绕过查询语法(因为我习惯于使用 XPath)。如果有人有 LINQ 解决方案,请告诉我。
这是我目前的代码(XPath 方法)
Private Function getAttributInclude(ByVal path2xml As String) As List(Of String)
Dim xmlDoc As XmlDocument = New XmlDocument()
Dim listAttributValues As New List(Of String)
Dim nodeAttributInsertValueSplitted() As String
Dim splittedStringMitEndungDll As String
Dim nsmanager As XmlNamespaceManager = New XmlNamespaceManager(xmlDoc.NameTable)
nsmanager.AddNamespace("msn", "http://schemas.microsoft.com/developer/msbuild/2003")
nsmanager.AddNamespace(String.Empty, "urn:test") 'default namespace
xmlDoc.Load(path2xml)
Dim nodeListAttributInclude As XmlNodeList
Dim root As XmlElement = xmlDoc.DocumentElement
nodeListAttributInclude = root.SelectNodes("/Project/ItemGroup/Reference/@Include")
Dim nodeAttributeInclude As XmlNode
Dim hintPath As XmlElement
For Each nodeAttributeInclude In nodeListAttributInclude
nodeAttributInsertValueSplitted = nodeAttributeInclude.Value.Split(",")
splittedStringMitEndungDll = String.Format("..\..\lib\{0}.dll", nodeAttributInsertValueSplitted(0))
listAttributValues.Add(nodeAttributeInclude.InnerText)
hintPath = xmlDoc.CreateElement("HintPath", nodeAttributeInclude.NamespaceURI)
hintPath.InnerText = splittedStringMitEndungDll
nodeAttributeInclude.ParentNode.AppendChild(hintPath)
Next
xmlDoc.Save(path2xml)
Return listAttributValues
我特别想知道为什么 .AppendChild 在这种情况下不起作用
在此先感谢您提供的任何帮助。
亲爱的
只是想给你一个更新。 我回到了项目并获得了一个很好的方法。然而,事实证明这只是朝着正确方向迈出的一步,我可能要为没有明确地写出我对原件的意图负责。新的sn-p如下: 将 xDoc 调暗为 XDocument = XDocument.Load(path2xml)
Dim nsmanager As New XmlNamespaceManager(New NameTable)
nsmanager.AddNamespace("ns", "http://schemas.microsoft.com/developer/msbuild/2003")
nsmanager.AddNamespace(String.Empty, "urn:test") 'default namespace
Dim ns As XNamespace = "http://schemas.microsoft.com/developer/msbuild/2003"
Dim xAttr = xDoc.XPathSelectElement("//ns:Reference", nsmanager).Attribute("Include").Value
Dim hpElement As New XElement(New XElement(ns + "HintPath", xAttr))
xDoc.XPathSelectElement("//ns:Reference", nsmanager).Add(hpElement)
xDoc.Save(path2xml)
到目前为止,正在相应地创建 XML 元素。但是,使用 Xpath 表达式,我想我会得到所有具有我正在寻找的属性的元素。此外,我最初希望获得一个节点列表,因为我将对包含该属性的每个节点/元素的属性字符串应用替换。事实证明,使用您的建议仅选择了第一个元素。 这是我的新问题: 1.是否可以使用此语法选择所有节点? 2.我将如何在每个属性节点中执行字符串替换 请参考我最初的帖子,向您展示我使用节点列表并迭代每个节点以进行替换的最初想法(这种方法有效,但我最终无法创建 XML-HintPath-element)。由于缺乏编程经验,我想我在此过程中感到困惑,对此感到抱歉 如果您或其他任何人能对这个主题有更多的了解,那就太好了。
更新: 我又看了一遍代码,有一点我完全不明白:重新检查了上面代码块中的每一行后,我遇到了以下行:
xDoc.XPathSelectElement("//ns:Reference", nsmanager).Add(hpElement)
参数和返回值的描述表示将检索单个值。我承认我错过了事先阅读该特定信息。但是,我看到复数版本,即 XPathSelectElements 也是可能的。根据我的理解,这似乎是一个很好的方法(以及一个轻微但太典型的错字)。将线路更改为
时令我感到惊讶xDoc.XPathSelectElements("//ns:Reference", nsmanager).Add(hpElement)
我说错了
Attribute is not a member of System.Collection.Generic.IEnumerable(Of System.Xml.Linq.XElement
这正是我不明白的。选择所有元素怎么会出错?以及如何获得由 XPAth 表达式选择的所有节点的列表以进行进一步处理?我现在很茫然。期待您的回复。
我尝试了在本论坛和其他论坛中找到的以下方法。
Dim xAttr = xDoc.XPathSelectElement("//ns:Reference", nsmanager).Attribute("Include").Value
Dim xAttr = xDoc.Root.Descendants("Reference").Attributes("Include")
Dim xAttr = xDoc.XPathEvaluate("//Reference/@Include")
但是,这些方法似乎都不起作用。我无法选择属性字符串并相应地执行替换。也许这有助于确定问题。
更新: 我再次查看了我之前的代码,并能够解决一些问题(参见下面发布的代码)。我现在可以选择我设想的所有节点。此外,在调试模式下,替换似乎也开始了。然而,这真的让我很恼火,我不知道如何用一些被替换的字符串添加新的。微软提供的例子
uses XmlNode root = doc.DocumentElement;
我想做的 aacomplish 我们使用元素的现有 Xpath 表达式。在尝试时,我通常会收到一个错误,即无法将对象“x”转换为对象“y”。有人可以帮我解决这个问题吗?
这是新代码
Private Function getAttributInclude(ByVal pfad2xml As String) As XmlDocument
Dim xDoc As New XmlDocument
xDoc.Load(pfad2xml)
Dim ns As XNamespace = "http://schemas.microsoft.com/developer/msbuild/2003"
Dim nsmanager As New XmlNamespaceManager(New NameTable)
nsmanager.AddNamespace("ns", "http://schemas.microsoft.com/developer/msbuild/2003")
nsmanager.AddNamespace(String.Empty, "urn:test")
Dim navigator As XPathNavigator = xDoc.CreateNavigator()
Dim xpathAttributInclude As XPathExpression = XPathExpression.Compile("//ns:Reference/ns:SpecificVersion/../@Include")
xpathAttributInclude.SetContext(nsmanager)
Dim xpathElementSpecificVersion As XPathExpression = XPathExpression.Compile("//ns:Reference/ns:SpecificVersion")
xpathElementSpecificVersion.SetContext(nsmanager)
Dim nodeListAttributInclude As XPathNodeIterator = navigator.Select(xpathAttributInclude)
Dim nodeListElementSpecificVersion As XPathNodeIterator = navigator.Select(xpathElementSpecificVersion)
Dim hintPath As XmlElement
For Each nodeAttributInclude In nodeListAttributInclude
Dim nodeAttributInsertValueSplitted = nodeAttributInclude.Value.Split(",")
Dim replacedNodeText As String
Dim splittedStringMitEndungDll
Dim replacedVersionAttribut As String
replacedNodeText = nodeAttributInsertValueSplitted(0).ToString.Replace( _
txtBoxEnterVersionNummerOld.Text, txtBoxEnterVersionNummerNew.Text)
writeLog(replacedNodeText + vbCrLf)
splittedStringMitEndungDll = String.Format("..\..\lib\{0}.dll", replacedNodeText)
writeLog(splittedStringMitEndungDll + vbCrLf)
If tbXmlDevExpressVersionNew.Text.Length > 0 Then
Dim splittedElementSpecificVersion = nodeAttributInsertValueSplitted(1).Split("=")
replacedVersionAttribut = splittedElementSpecificVersion(1).ToString.Replace( _
splittedElementSpecificVersion(1).ToString, tbXmlDevExpressVersionNew.Text)
writeLog(replacedVersionAttribut + vbCrLf)
Else
MessageBox.Show("Please enter a valid version numbers")
End If
hintPath = xDoc.CreateElement("HintPath", nodeAttributInclude.NamespaceURI)
hintPath.InnerText = splittedStringMitEndungDll
Dim node2insertAfter = xDoc.DocumentElement
For Each nodeElementSpecificVersion In nodeListElementSpecificVersion
xDoc.InsertAfter(hintPath, node2insertAfter.SelectSingleNode("//Reference/SpecificVersion"))
writeLog(nodeElementSpecificVersion.ToString + vbCrLf)
Next
Next
xDoc.Save("c:\tmp\result_xml.xml")
Return xDoc
End Function
更新: 我遇到了一个interesting article,它为解决方案提供了一个链球菌。但是,尽管我在循环中使用循环,但我仍然遇到问题元素仅附加到最后一项的问题。此外,替换似乎也没有生效。这是调整后的 appendChild 部分的 sn-p,用于添加 XML 元素
For Each nodeElementReference In nodeListElementReference
Dim node2StartInsert = DirectCast(nodeElementReference, System.Xml.IHasXmlNode).GetNode
node2StartInsert.AppendChild(hintPath)
Next
提前感谢您的帮助。
亲切的问候 萨斯
我设法找到了解决方案。但是,代码只需要提取属性,该属性现在正确地出现在此代码应用到的输入 XML 中。使用 XMLElement 和 XPathNavigator 提供了将附加元素写入现有 XML 文件的方法。
Dim hintPath As XmlElement
Dim nodeAttributInclude As XPathNavigator
For Each nodeAttributInclude In nodeListAttributInclude
Dim nodeAttributInsertValueSplitted = nodeAttributInclude.Value.Split(",")
Dim versionsInfoText As String
Dim splittedStringMitEndungDll
versionsInfoText = nodeAttributInsertValueSplitted(0).ToString
splittedStringMitEndungDll = String.Format("..\..\lib\{0}.dll", versionsInfoText)
nodeAttributInclude.MoveToParent()
hintPath = xDoc.CreateElement("HintPath")
hintPath.InnerText = splittedStringMitEndungDll
nodeAttributInclude.AppendChild("<HintPath>" + hintPath.InnerText + "</HintPath>")
Next
xDoc.Save("c:\tmp\result_xml.xml")
【问题讨论】:
-
更新:我做了一些检查,发现 XPath 符号似乎没有被评估。我尝试了相对和绝对路径表示法。但是,仅选择 //@Include 会产生预期的节点列表。我不确定,但我认为 XPath 实现可能已损坏。如果有人可以添加解释,那就太好了。
-
有人指出不清楚哪些文档是我的源文件和目标文件。输入文件是此处发布的 XML。输出文件应该是相同的,但添加了额外的 XML 元素(
应该因此得到另一个名为 的子项,该子项又包含修改后的子字符串)。我希望这有助于进一步讨论 -
为了更准确地了解错误。问题是“System.Xml.XmlNodeList”无法转换为“System.Xml.XmlNode”。问题是如果不使用节点列表,我应该如何到达为 InsertAfter 找到正确位置所需的节点。我还认为循环会解决这个问题。我现在很困惑,不知所措。