【问题标题】:Adding data to a node of an xml file in visual basic在visual basic中将数据添加到xml文件的节点
【发布时间】:2013-03-25 13:41:05
【问题描述】:

我是 Visual Basic 的新手,所以我想从一开始就原谅自己。

下面的代码应该得到一个节点列表,其中包含NameInnerText 等于名为membername 的字符串的所有节点。这部分似乎工作得很好,但之后我还想检查这个列表中是否已经存在节点Logout。这样我想防止重复xml数据库中的数据。不幸的是,它不像我尝试的那样工作。它不断复制所有数据。那么我的错误是什么??

XML 文件

<?xml version="1.0" encoding="utf-16"?>
<Times>
  <Shift>
    <Name>Philipp</Name>
    <Login>14:11</Login>
    <Date>25.03.2013</Date>
    <Logout>14:11</Logout> ' Don't generate again ....
  </Shift>
  <Shift>
    <Name>Philipp</Name>
    <Login>14:11</Login>
    <Date>25.03.2013</Date>
    <Logout>14:11</Logout> ' Generate Logout node
  </Shift>
</Times>

视觉基本代码

   If File.Exists(Filename) Then

        DOMDocument.Load(Filename)

        Dim RootElement As XmlElement = DOMDocument.DocumentElement
        Dim ListOfTitles As XmlNodeList = DOMDocument.GetElementsByTagName("Name")

        For Each Node As XmlNode In ListOfTitles

            If Node.InnerText = memberName Then

                Dim logout = Node.SelectNodes("Logout")

                If Not logout Is Nothing Then

                    Dim NewElement As XmlElement = DOMDocument.CreateElement("Logout")
                    NewElement.InnerText = DateTime.Now.ToShortTimeString()

                    Dim Parent As XmlNode = Node.ParentNode
                    Parent.AppendChild(NewElement)

                    DOMDocument.Save(Filename)

                End If

            End If

        Next
    End If

【问题讨论】:

  • 我将您的标签从“vb6”更改为“vb.net”。
  • 我 +1 了 GojiraDeMonstah 的回答。如果还不算太晚,如果您的代码少于 1000 行,请尽可能快地运行此 XML 运行、RUN、RUNNNN,而不要直接操作 XML 并使用对象运行 TO。我无法强调能够以 1/3 的错误速度以 3 倍的速度编写代码将是多么美妙。我只能说,相信我,你会喜欢的。
  • 我错了吗,或者InnerText应该只是Text

标签: xml vb.net


【解决方案1】:

logout 被设置为一个空对象,所以If Not logout is Nothing Then 等价于If True Then。见:http://msdn.microsoft.com/en-us/library/hcebdtae.aspxIXMLElement.selectNodes(expression) 方法总是返回一个对象。要修复,请检查 logout 的长度值。

If logout.Count &gt; 0 Then 或使用selectSingleNode,如果没有找到节点,则返回NULL

【讨论】:

  • 能否请您添加一些更详细的代码? logout.length 不起作用。我尝试将它与选择单节点一起使用。而且您的链接是指 c# 和 c++ 链接。
  • @PhilippBraun 该链接指的是您在 VB6 中使用的 MS XML(诚然是 WinCE 版本)。大多数 MSDN 文档都是用 C++ 编写的。
  • 坦克,但我仍然不知道如何在这里使用 .length。
  • @Philipp Braun,Motes 说的是用“If logout.length > 0 Then”替换您的“If Not logout is Nothing Then”或替换“Dim logout = Node.SelectNodes("Logout ")" 与 "Dim logout = Node.SelectSingleNode("Logout")"
  • @PhilippBraun - 应该是logout.Count &gt; 0
【解决方案2】:

让我们试着解释什么是错误的以及如何解决它。

显然,您希望为每个&lt;Name&gt;node 检索与其关联的&lt;Logout&gt; 节点(如果存在),并且您尝试Node.SelectNodes("Logout") 执行此操作,但是:

Node.SelectNodes("Logout") 代码实际上尝试选择 &lt;Name&gt; 节点的 child 节点,该节点由您的 Node 变量表示 - 而在您的 XML 标记中,

  1. &lt;Name&gt; 节点没有子节点和

  2. &lt;Logout&gt; 节点始终是它们的兄弟节点,而不是子节点。

所以它总是返回一个空集合,而不是你想要的节点。

您可以通过迭代 &lt;Shift&gt; 节点来解决此问题,因为它们包含名称和注销信息作为子节点。

顺便说一句,InnerText 不是 IXMLDOMNode 属性,请尝试改用Text

If File.Exists(Filename) Then

    DOMDocument.Load(Filename)

    Dim RootElement As XmlElement = DOMDocument.DocumentElement
    Dim ListOfShifts As XmlNodeList = DOMDocument.GetElementsByTagName("Shift")

    For Each ShiftNode As XmlNode In ListOfShifts

        Dim NameNode = ShiftNode.SelectSingleNode("Name")
        If NameNode IsNot Nothing And NameNode.Text = memberName Then

            Dim logoutNode = ShiftNode.SelectSingleNode("Logout")

            If Not logoutNode Is Nothing Then

                Dim NewElement As XmlElement = DOMDocument.CreateElement("Logout")
                NewElement.Text = DateTime.Now.ToShortTimeString()

                Dim Parent As XmlNode = Node.ParentNode
                Parent.AppendChild(NewElement)

                DOMDocument.Save(Filename)

            End If

        End If

    Next
End If

此外,您在每次更改时都保存文档 - 为什么不在循环完成后只保存一次

【讨论】:

    【解决方案3】:

    这并不是您要问的,但我发现处理原始 XML 会导致很多麻烦。相反,您可能会考虑处理一个 Shift 类,该类允许您在登录/注销时执行逻辑,并让 .NET 为您执行序列化/反序列化。

    这样,如果您的业务对象和关系发生变化,您就不会被绑定到特定的 XML 路径。

    再说一次,不是您问的问题,而是我将如何解决您正在处理的业务案例。

    首先,创建一个我可以放入业务逻辑的班次类。这里的简单示例:

    Public Class Shift
    
        Public Property Name As String
        Public Property DateString As String
        Public Property Login As String
        Public Property Logout As String
    
    End Class
    

    接下来,创建一个班次集合。我称这个类为 TimeCollection,但你可以随意调用它。将其标记为 Serializable,以便 .NET 可以将其从对象转换为 XML,反之亦然。

    Imports System
    Imports System.Collections.Generic
    Imports System.Linq
    Imports System.Text
    Imports System.IO
    Imports System.Xml.Serialization
    
    <Serializable()> Public Class TimeCollection
    
    Public Property Path As String
    
    <XmlArray("Shifts")>
    <XmlArrayItem(GetType(Shift))>
    Public Property Shift As Shift()
    
    Public Function Serialize(FileInfo As System.IO.FileInfo)
        Try
    
            If File.Exists(FileInfo.FullName) Then
                File.Delete(FileInfo.FullName)
            End If
    
            If Not Directory.Exists(FileInfo.DirectoryName) Then
                Directory.CreateDirectory(FileInfo.DirectoryName)
            End If
    
            Me.Path = FileInfo.FullName
    
            Dim serializer As XmlSerializer = New XmlSerializer(GetType(TimeCollection))
            Dim writer As StreamWriter = New StreamWriter(FileInfo.FullName)
    
            serializer.Serialize(writer, Me)
            writer.Close()
    
        Catch ex As Exception
    
            Throw
        End Try
    
    End Function
    
    Public Shared Function Deserialize(FileInfo As FileInfo) As TimeCollection
    
    
        Dim serializedType As TimeCollection = Nothing
    
        Dim path As String = FileInfo.FullName
    
        If (Not File.Exists(path)) Then
            Deserialize = serializedType
        Else
            Try
                Dim serializer As XmlSerializer = New XmlSerializer(GetType(TimeCollection))
                Dim reader As StreamReader = New StreamReader(path)
                serializedType = serializer.Deserialize(reader)
                reader.Close()
                Deserialize = serializedType
            Catch ex As Exception
                Console.WriteLine(ex.Message)
            End Try
        End If
    
    End Function
    
    End Class
    

    现在。如果你有一些代码会产生一系列的转变,像这样:

        Dim tc As TimeCollection = New TimeCollection() 
    
        Dim first As Shift = New Shift()
        first.Name = "Philipp"
        first.Login = "14:11"
        first.Logout = "14:45"
        first.DateString = "3/31/2013"
    
        Dim second As Shift = New Shift()
        second.Name = "Phillip"
        second.Login = "14:09"
        ' second.Logout = "15:01" (note 2nd shift has no logout)
        second.DateString = "4/1/2013"
    
        tc.Shift = New Shift(1) {first, second}
    

    您可以像这样轻松地序列化 TimeCollection 对象:

    tc.Serialize(New FileInfo("C:\SomePath\TimeCollectionA.xml"))
    

    创建以下内容:

       <?xml version="1.0" encoding="utf-8"?>
    <TimeCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Path>C:\Temp\Tc.xml</Path>
      <Shifts>
        <Shift>
          <Name>Philipp</Name>
          <DateString>3/31/2013</DateString>
          <Login>14:11</Login>
          <Logout>14:45</Logout>
        </Shift>
        <Shift>
          <Name>Phillip</Name>
          <DateString>4/1/2013</DateString>
          <Login>14:09</Login>
        </Shift>
      </Shifts>
    </TimeCollection>
    

    然后,要反序列化内容并将文件转换回对象集合,您可以执行以下操作:

        Dim tc As TimeCollection
        tc = TimeCollection.Deserialize(New FileInfo("C:\SomePath\TimeCollectionA.xml"))
    

    现在您可以遍历 tc.Shift 数组等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多