簡體   English   中英

在VB.Net中的XML上存儲屬性

[英]Storing Attributes on XML in VB.Net

我已經使用這種通用格式創建了XML,並且在存儲屬性時遇到了困難:

<?xml version="1.0">
-<Report>
    -<Class Name="ClassA">
        <Property Name="Property1" dType="Boolean">False</Property>
    </Class>
    -<Class Name="ClassB">
        -<Property Name="Property2" dType="SortedList`2" Value="String" Key="Int16">
            <SrtLstItm Key="1">94</SrtLstItm>
        </Property>
        <Property Name="Property3" dType="Int32">1</Property>
        -<Property Name="Property4" dType="List`1" Type="Product">
            <LstItm Name="Property4">LstItm1</LstItm>
            <LstItm Name="Property4">LstItm2</LstItm>
        </Property>
    </Class>
    -<Class Name="ClassC">
        <Property Name="Property5" dType="String">50.5</Property>
    </Class>
</Report>

我感興趣的是使用XMLTextReader存儲類名稱,以便它在讀取屬性時仍具有類信息。 我當前正在通過NodeType使用Select Case:

Dim xrdr = New System.Xml.XmlTextReader(fileName)
Do While (xrdr.Read())
  Select Case xrdr.NodeType
    Case XmlNodeType.Element 'Display beginning of element.'
      Select Case xrdr.Name
        Case xrdr.Name = "Class"
          cls = xrdr.GetAttribute("Name")
        Case xrdr.Name = "Property"
          propertyName = xrdr.GetAttribute("Name")
        Case xrdr.Name = "SrtListItm"
          srtLstKey = xrdr.GetAttribute("Key")
      End Select
      If xrdr.HasAttributes Then 'If attributes exist'
        While xrdr.MoveToNextAttribute()
          ''Display attribute name and value.              
        End While
      End If
    Case XmlNodeType.Text 'Display the text in each element.'
      vle = xrdr.ReadString
    Case XmlNodeType.EndElement 'Display end of element.'
  End Select
Loop
xrdr.Close()

我計划使用代碼用XML中給出的更新值來更新每個類的公共屬性。 在此之前,我擁有XML,因此每個屬性都具有一個class屬性,並且代碼將能夠讀取和更新所有沒有子級的屬性。 我正在對其進行重組以考慮數組類型的屬性。 任何幫助將不勝感激,並感謝您的時間。

更新:使用發布的解決方案,我提出了以下建議。 從上面的代碼中,我能夠讀取所有非數組屬性。 現在,我嘗試從孩子中導入值。

Dim xrdr = New System.Xml.XmlTextReader(fileName)
Do While (Not xrdr.EOF)
  xrdr.ReadToFollowing("Class")
  If (Not xrdr.EOF) Then
    Dim _class As XElement = XElement.ReadFrom(xrdr)
    Dim cls As String = _class.Attribute("Name")
    For Each _property As XElement In _class.Elements("Property")
      Dim propertyName As String = _property.Attribute("Name")
      fInfo = ps.GetType().GetField("_" & cls,
           System.Reflection.BindingFlags.NonPublic Or
           System.Reflection.BindingFlags.Instance Or
           System.Reflection.BindingFlags.Public Or
           System.Reflection.BindingFlags.IgnoreCase)
      'Use the FieldInfo to retrieve the sub-class the matches the cls variable.'
        obj = fInfo.GetValue(object)'Object created before read'

      'Using reflection, get the PropertyInfo of the Property that matches'
      'the text in the nme variable.'
      pInfo = obj.GetType.GetProperty(propertyName)
      If pInfo Is Nothing Then

      Else
        Dim pInfoType = pInfo.PropertyType.Name

        If pInfoType = "SortedList`2" Then
          For Each _child As XElement In _property.Elements("SrtLstItm")
            Dim childName As String = _child.Attribute("Key")
            pInfo = obj.GetType.GetProperty(childName)
            tmpVal = CTypeDynamic(_child.Value, pInfo.PropertyType)
            pInfo.SetValue(obj, tmpVal, Nothing)
          Next
        ElseIf pInfoType = "List`1" Then
        ElseIf pInfoType = "Product" Then
        Else
          'Convert the value (vle) to the type of the Property to which
          'it will be assigned.  CTypeDynamic must be used so that the
          'type retrieved from pInfo can be used.
          tmpVal = CTypeDynamic(_property.Value, pInfo.PropertyType)
          'Use the PropertyInfo to set the value of the property
          'that matches nme. 
          pInfo.SetValue(obj, tmpVal, Nothing)
        End If

      End If

    Next _property

  End If
Loop

這是將XmlTextReader與linq結合使用的簡單得多的方法

Imports System.Xml
Imports System.Xml.Linq
Module Module1
    Const FILENAME As String = "c:\temp\test.xml"
    Sub Main()
        Dim xrdr = New System.Xml.XmlTextReader(FILENAME)
        Do While (Not xrdr.EOF)
            xrdr.ReadToFollowing("Class")
            If (Not xrdr.EOF) Then
                Dim _class As XElement = XElement.ReadFrom(xrdr)
                Dim results = GetClass(_class)
            End If
        Loop

    End Sub
    Function GetClass(_class As XElement) As Object
        Return _class.DescendantsAndSelf().Select(Function(x) New With {
                 .name = x.Attribute("Name").Value,
                 .properties = x.Elements("Property").Select(Function(y) New With {
                        .name = CType(y.Attribute("Name"), String),
                        .dType = CType(y.Attribute("dType"), String),
                        .value = CType(y.Attribute("Value"), String),
                        .key = CType(y.Attribute("Key"), String),
                        .sortedLstItm = y.Elements("SrtLstItm").Select(Function(z) New With {
                                .key = CType(z.Attribute("Key"), String),
                                .value = Integer.Parse(z.Value)
                        }).ToList(),
                        .lstItms = y.Elements("LstItm").Select(Function(z) New With {
                            .name = CType(z.Attribute("Name"), String),
                            .value = z.Value
                        }).ToList()
                  }).ToList()
        }).FirstOrDefault()
    End Function
End Module

使用您的示例,我提出了兩種遍歷DOM的方法。 第一個使用XmlDocument,第二個使用XmlTextReader。 我將兩者都放入一個將信息輸出到TextBox的示例中。 我這樣做是為了防止您發現使用XmlDocument來跟蹤您所處的級別更容易。 在任何一種情況下,您都需要捕獲每個唯一元素(類,屬性,屬性子級等)的開始並相應地使用。

這是我創建的用於解析文件的單個子文件:

Private Sub ReadXmlData(ByRef fileName As String)

  Dim cls As String = String.Empty
  Dim propertyName As String = String.Empty
  Dim srtLstKey As String = String.Empty
  Dim vle As String = String.Empty
  Dim counter As Integer = 0

  Dim output As StringBuilder = New StringBuilder()

  '
  '-- METHOD 1: XmlDocument --
  '

  'Notice how this one could benefit from recursive calls to a single function due to the nested child nodes.

  Dim xDoc As XmlDocument = New XmlDocument()
  xDoc.Load(fileName)

  Dim node As XmlNode
  Dim child As XmlNode
  Dim child2 As XmlNode
  Dim attr As XmlAttribute
  counter = 1
  For Each node In xDoc.DocumentElement.ChildNodes
     output.AppendLine("#" & counter.ToString() & ": " & node.Name)
     For Each attr In node.Attributes
        output.AppendLine("Attribute [" & attr.Name & "] = " & attr.Value)
     Next
     If node.HasChildNodes Then
        For Each child In node.ChildNodes
           output.AppendLine("-- Child [" & child.Name & "] = " & child.Name)
           If child.InnerText.Length > 0 Then output.AppendLine("---- (Text): " & child.InnerText)
           If child.Attributes IsNot Nothing Then
              For Each attr In child.Attributes
                 output.AppendLine("---- Attribute [" & attr.Name & "] = " & attr.Value)
              Next
           End If
           If child.HasChildNodes Then
              For Each child2 In child.ChildNodes
                 output.AppendLine("------ Child [" & child2.Name & "] = " & child2.Name)
                 If child2.InnerText.Length > 0 Then output.AppendLine("------ (Text): " & child2.InnerText)
                 If child2.Attributes IsNot Nothing Then
                    For Each attr In child2.Attributes
                       output.AppendLine("------ Attribute [" & attr.Name & "] = " & attr.Value)
                    Next
                 End If
              Next
           End If
        Next
     End If
     counter += 1
  Next
  output.Append("=", 30)
  output.AppendLine()

  '
  '-- METHOD 2: XmlTextReader --
  '

  Dim xrdr = New System.Xml.XmlTextReader(fileName)

  counter = 1
  Do While (xrdr.Read())
     If xrdr.NodeType = XmlNodeType.Element Then
        output.Append("-", 20)
        output.Append(" " & counter.ToString() & " ")
        output.Append("-", 20)
        output.AppendLine()
        counter += 1
     End If
     output.AppendLine(xrdr.NodeType.ToString())
     Select Case xrdr.NodeType
        Case XmlNodeType.Element 'Display beginning of element.
           output.AppendLine("NODETYPE -- Name: " & xrdr.Name)
           Select Case xrdr.Name
              Case "Class"
                 cls = xrdr.GetAttribute("Name")
                 output.AppendLine("Class: " & cls)
              Case "Property"
                 propertyName = xrdr.GetAttribute("Name")
                 output.AppendLine("Property: " & propertyName)
              Case "SrtLstItm"
                 srtLstKey = xrdr.GetAttribute("Key")
                 output.AppendLine("SrtLstItm Key: " & srtLstKey)
              Case "LstItm"
                 output.AppendLine("LstItm: Name=" & xrdr.GetAttribute("Name"))
           End Select
           If xrdr.HasAttributes Then 'If attributes exist
              While xrdr.MoveToNextAttribute()
                 output.AppendLine("Attribute [" & xrdr.Name & "] = " & xrdr.Value)
              End While
           End If
        Case XmlNodeType.Text 'Display the text in each element.
           vle = xrdr.ReadString
           output.AppendLine("(Text): " & vle)
        Case XmlNodeType.EndElement 'Display end of element.
           output.Append("-", 10)
           output.Append(" [End Element] ")
           output.Append("-", 10)
           output.AppendLine()
     End Select
  Loop
  xrdr.Close()

  XmlOutput.Text = output.ToString()
End Sub

XmlOutput的輸出如下所示。 忽略語法突出顯示。 我無法使用blockquote,因為它正在解析各種字符作為標記。

#1: Class
Attribute [Name] = ClassA
-- Child [Property] = Property
---- (Text): False
---- Attribute [Name] = Property1
---- Attribute [dType] = Boolean
------ Child [#text] = #text
------ (Text): False
#2: Class
Attribute [Name] = ClassB
-- Child [Property] = Property
---- (Text): 94
---- Attribute [Name] = Property2
---- Attribute [dType] = SortedList`2
---- Attribute [Value] = String
---- Attribute [Key] = Int16
------ Child [SrtLstItm] = SrtLstItm
------ (Text): 94
------ Attribute [Key] = 1
-- Child [Property] = Property
---- (Text): 1
---- Attribute [Name] = Property3
---- Attribute [dType] = Int32
------ Child [#text] = #text
------ (Text): 1
-- Child [Property] = Property
---- (Text): LstItm1LstItm2
---- Attribute [Name] = Property4
---- Attribute [dType] = List`1
---- Attribute [Type] = Product
------ Child [LstItm] = LstItm
------ (Text): LstItm1
------ Attribute [Name] = Property4
------ Child [LstItm] = LstItm
------ (Text): LstItm2
------ Attribute [Name] = Property4
#3: Class
Attribute [Name] = ClassC
-- Child [Property] = Property
---- (Text): 50.5
---- Attribute [Name] = Property5
---- Attribute [dType] = String
------ Child [#text] = #text
------ (Text): 50.5
==============================
XmlDeclaration
Whitespace
-------------------- 1 --------------------
Element
NODETYPE -- Name: Report
Whitespace
-------------------- 2 --------------------
Element
NODETYPE -- Name: Class
Class: ClassA
Attribute [Name] = ClassA
Whitespace
-------------------- 3 --------------------
Element
NODETYPE -- Name: Property
Property: Property1
Attribute [Name] = Property1
Attribute [dType] = Boolean
Text
(Text): False
Whitespace
EndElement
---------- [End Element] ----------
Whitespace
-------------------- 4 --------------------
Element
NODETYPE -- Name: Class
Class: ClassB
Attribute [Name] = ClassB
Whitespace
-------------------- 5 --------------------
Element
NODETYPE -- Name: Property
Property: Property2
Attribute [Name] = Property2
Attribute [dType] = SortedList`2
Attribute [Value] = String
Attribute [Key] = Int16
Whitespace
-------------------- 6 --------------------
Element
NODETYPE -- Name: SrtLstItm
SrtLstItm Key: 1
Attribute [Key] = 1
Text
(Text): 94
Whitespace
EndElement
---------- [End Element] ----------
Whitespace
-------------------- 7 --------------------
Element
NODETYPE -- Name: Property
Property: Property3
Attribute [Name] = Property3
Attribute [dType] = Int32
Text
(Text): 1
Whitespace
-------------------- 8 --------------------
Element
NODETYPE -- Name: Property
Property: Property4
Attribute [Name] = Property4
Attribute [dType] = List`1
Attribute [Type] = Product
Whitespace
-------------------- 9 --------------------
Element
NODETYPE -- Name: LstItm
LstItm: Name=Property4
Attribute [Name] = Property4
Text
(Text): LstItm1
Whitespace
-------------------- 10 --------------------
Element
NODETYPE -- Name: LstItm
LstItm: Name=Property4
Attribute [Name] = Property4
Text
(Text): LstItm2
Whitespace
EndElement
---------- [End Element] ----------
Whitespace
EndElement
---------- [End Element] ----------
Whitespace
-------------------- 11 --------------------
Element
NODETYPE -- Name: Class
Class: ClassC
Attribute [Name] = ClassC
Whitespace
-------------------- 12 --------------------
Element
NODETYPE -- Name: Property
Property: Property5
Attribute [Name] = Property5
Attribute [dType] = String
Text
(Text): 50.5
Whitespace
EndElement
---------- [End Element] ----------
Whitespace
EndElement
---------- [End Element] ----------

請注意,不一定總是需要InnerText,例如具有LstItm屬性的Property。 但是,這應該使您開始尋找所需的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM