【问题标题】:Adding an element to an XML-document with a previously newly created string from an attribute node使用先前从属​​性节点创建的字符串将元素添加到 XML 文档
【发布时间】: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 元素中(即&lt;HintPath&gt;xyz&lt;/HintPath&gt;)。一旦我解决了命名空间问题(感谢 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 找到正确位置所需的节点。我还认为循环会解决这个问题。我现在很困惑,不知所措。

标签: xml vb.net linq xpath


【解决方案1】:

我设法找到了解决方案。但是,代码只需要提取属性,该属性现在正确地出现在此代码应用到的输入 XML 中。同时使用 XMLElement 和 XPathNavigator 提供了将附加元素写入现有 XML 文件的方法。 暗淡提示路径作为 XmlElement 暗淡 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")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    • 1970-01-01
    • 2019-06-17
    相关资源
    最近更新 更多