4

我对 Visual Basic 还是很陌生,所以我想从一开始就原谅自己。

下面的代码应该得到一个节点列表,其中的所有节点InnerText等于Name名为的字符串membername。这部分似乎工作得很好,但之后我还想检查这个列表中是否Logout已经存在一个节点。这样我想防止重复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
4

3 回答 3

3

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

If logout.Count > 0 Then或者如果没有找到节点,则使用selectSingleNodewhich 返回。NULL

于 2013-03-25T17:07:39.113 回答
2

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

显然,对于每个<Name>节点,您希望检索<Logout>与其关联的节点(如果存在),并且您尝试Node.SelectNodes("Logout")这样做,但是:

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

  1. <Name>节点没有子节点并且

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

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

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

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

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

于 2013-04-02T23:17:50.017 回答
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 数组等。

于 2013-03-30T22:36:20.953 回答