在visual basic中将数据添加到xml文件的节点

时间:2013-03-25 13:41:06

标签: xml vb.net

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

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

XML文件

Logout

VISUAL BASIC CODE

<?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>

3 个答案:

答案 0 :(得分:3)

logout被设置为空对象,因此If Not logout is Nothing Then等同于If True Then。见:http://msdn.microsoft.com/en-us/library/hcebdtae.aspx。方法IXMLElement.selectNodes(expression)始终返回一个对象。要修复,请检查注销的长度值。

If logout.Count > 0 Then或使用selectSingleNode,如果找不到节点则返回NULL

答案 1 :(得分:2)

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

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

在您的XML标记中,代码Node.SelectNodes("Logout")实际上会尝试选择<Name>变量所代表的Node节点的节点,

  1. <Name>个节点没有子节点

  2. <Logout>节点总是他们的兄弟姐妹,而不是孩子。

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

    您可以通过遍历<Shift>节点来解决此问题,因为它们包含Name和Logout信息作为子节点。

    顺便说一下,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
    

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

答案 2 :(得分:1)

这不完全是你所要求的,但我发现处理原始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数组等。