2016-03-30 8 views
0

Ich habe eine XML mit diesem allgemeinen Format erstellt und habe Schwierigkeiten zu speichern Attribute:Speicher Attribute auf XML in VB.Net

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

Was ich bin interessiert dabei verwendet XMLTextReader Klassennamen zu speichern, um sie liest durch die Eigenschaften es hat immer noch Klasseninformationen. Ich bin derzeit mit Select Case von NodeType:

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() 

Ich plane, den Code über die Verwendung der öffentlichen Eigenschaften jeder Klasse mit aktualisierten Werte in der XML gegeben zu aktualisieren. Davor hatte ich das XML, also hatte jede Eigenschaft ein Klassenattribut und der Code konnte alle Eigenschaften lesen und aktualisieren, die keine Kinder hatten. Ich umstrukturiere es, um Eigenschaften des Array-Typs zu berücksichtigen. Jede Hilfe wäre willkommen und ich danke Ihnen für Ihre Zeit.

Update: mit der Lösung veröffentlicht, kam ich mit dem folgenden. Aus dem obigen Code konnte ich alle Nicht-Array-Eigenschaften einlesen. Jetzt versuche ich die Werte von den Kindern zu importieren.

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 

Antwort

2

ist hier eine viel einfachere Art und Weise der Verwendung von XmlTextReader mit 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 
+0

Ich bin ein wenig vertraut mit linq. Von Ihrem Code kann ich _property.value bekommen, aber im Falle von sortierten Listen und Listen, wie bekomme ich diese multiplen Werte? –

+0

Ich habe den Code aktualisiert. Das ist in C# so viel einfacher. – jdweng

1

Mit Ihrem Beispiel habe ich zwei Wege gefunden, um das DOM zu gehen. Der erste verwendet ein XmlDocument und der zweite den XmlTextReader. Ich gebe beide in ein Beispiel ein, das Informationen an eine TextBox ausgibt. Ich habe es auf diese Weise gemacht, falls Sie es einfacher finden, mit dem XmlDocument zu verfolgen, auf welcher Ebene Sie sich befinden. In jedem Fall müssen Sie den Anfang jedes einzelnen Elements (Klasse, Eigenschaft, die untergeordneten Objekte usw.) abfangen und entsprechend verwenden.

Dies ist die einzige Unter ich geschaffen, um Ihre Datei zu analysieren:

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 

Die Ausgabe an xmloutput sieht wie folgt aus. Ignorieren Sie die Syntaxhervorhebung. Ich konnte blockquote nicht verwenden, weil verschiedene Zeichen als Markup analysiert wurden.

#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] ---------- 

Beachten Sie, dass nicht immer gewünscht Inner werden kann, wie zum Beispiel mit der Eigenschaft, dass LstItm Eigenschaften hat. Aber das sollte dich dazu bringen, das zu finden, was du brauchst.

+0

Sie Chris danken. Mit Methode 2 bekomme ich immer noch keinen Wert für cls. –

+0

@MatthewKruse - cls füllt sich gut. Hier ist, wo ich es haben ausgibt: 'output.AppendLine ("Klasse:" & cls)' Also, in der Ausgabe, es ist direkt hier: > NODETYPE - Name: Klasse > Attribut [Name] = ** ClassB ** Zusätzliche Attribute befinden sich im Block 'If xdr.HasAttributes ...'. –

+0

Entschuldigung. Korrektur. Hmm. Du hast recht. Es zieht als Teil der Zeile "If xdr.HasAttributes". Vielleicht müssen Sie den 'xdr.MoveToNextAttribute()' Aufruf machen, bevor Sie versuchen, es zu bekommen. Der Leser funktioniert nicht wie ein Dokument. –