VB.NET Query Linq用于获取所有元素节点

时间:2015-11-19 09:32:40

标签: xml vb.net linq

我试图在Linq中理解XML并且我有这个文件XML:

<?xml version="1.0" encoding="utf-8"?>
<Headers  xmlns="http://tempuri.org/GridLayerSchema.xsd">
  <Header>
   <Name>Layer0</Name>
    <Fields FieldID="FieldID0" FieldName="FieldNameAll" FieldPosition="0" FieldPositionStart="0" FieldLenght="254" FieldEnable="true" />
   </Header>
  <Header>
   <Name>Layer1</Name>
   <Fields FieldID="FieldID0" FieldName="JetPosition" FieldPosition="0" FieldPositionStart="0" FieldLenght="14" FieldEnable="true" />
   <Fields FieldID="FieldID1" FieldName="Owner" FieldPosition="1" FieldPositionStart="14" FieldLenght="14" FieldEnable="true" />
   <Fields FieldID="FieldID2" FieldName="Item" FieldPosition="2" FieldPositionStart="28" FieldLenght="3" FieldEnable="true" />
  </Header>
</Headers>

我将尝试使用linq查询获取所有元素来制作VB.net类,有些想法是这样的:

 Class Field:
  Public Class Field
  Public Property FieldID1 As String
  Public Property FieldName As String
  Public Property FieldPosition As Integer
  Public Property FieldPositionStart As Integer
  Public Property FieldLenght As Integer
  Public Property FieldEnable As Boolean
End Class

然后是Header类:

Public Class Header : Inherits Field
  Public Property Name As String
End Class

在这一个中,我是一个制作Headers系列的功能:

Public Shared Function HeadersLoader() As Headers
    Dim HeadersCollection As New Headers
    Dim ns As XNamespace = "http://tempuri.org/GridLayerSchema.xsd"
    Dim xdoc As XDocument = XDocument.Load(My.Application.Info.DirectoryPath & "\Layers\Headers.xml")

     Dim HeadersQuery = From Header In xdoc.Root.Elements(ns + "Header")
                       Select Header
    For Each e In HeadersQuery
        Dim _mHeader As New Header
        With _mHeader
            .Name = e.Value.ToString
        End With
        HeadersCollection.Add(_mHeader)
    Next
    Return HeadersCollection
   End Function

现在我有两个问题:

  • 为什么我在Value属性中有Header的名称,而不在Name属性中(在name属性中我有所有的名称空间和标题标记,但不是名称:{http://tempuri.org/GridLayerSchema.xsd} Header)

  • 如何读取当前标题的所有字段?我需要嵌套查询吗?我想,通过我的查询,找到所有但似乎不是这样,我只能读取第一个节点。

2 个答案:

答案 0 :(得分:1)

Value上的XElement属性将连接元素中的所有文本节点,包括后代中的文本节点,这让您感到困惑。 发生以获取Name子元素的文本值,因为这是您使用任何文本获得的唯一元素。最好写一下:

With _mHeader
    .Name = e.Element(ns + "Name").Value

通过这种方式,您明确要求<Name>子元素中的文字。

现在你的课堂设计有点乱,因为你说的是​​标题是一个字段,而不是 一个字段列表。我想你应该有类似的东西:

Public Class Header
  Public Property Name As String
  Public Property Fields As List(Of Field)
End Class

(可能有一些初始化)。然后,我将更改您的LINQ查询,以在Header子句中创建Select的实例。我不打算尝试VB,但在C#中我会有类似的东西:

var headers = xdoc.Root.Elements(ns + "Header")
                  .Select(header => new Header
                  {
                      Name = header.Element("Name").Value,
                      Fields = header.Elements("Fields")
                                     .Select(field => new Field
                                     {
                                         FieldID1 = field.Element("FieldID)".Value,
                                         // etc
                                     })
                                     .ToList();
                  });

您可能希望将静态FromXElement方法添加到HeaderField(其中Header.FromXElement将使用Field.FromXElement)以使这一切变得更加简单。

答案 1 :(得分:0)

Sub Main()

    Dim xml = <?xml version="1.0" encoding="utf-8"?>
              <Headers xmlns="http://tempuri.org/GridLayerSchema.xsd">
                  <Header>
                      <Name>Layer0</Name>
                      <Fields FieldID="FieldID0" FieldName="FieldNameAll" FieldPosition="0" FieldPositionStart="0" FieldLenght="254" FieldEnable="true"/>
                  </Header>
                  <Header>
                      <Name>Layer1</Name>
                      <Fields FieldID="FieldID0" FieldName="JetPosition" FieldPosition="0" FieldPositionStart="0" FieldLenght="14" FieldEnable="true"/>
                      <Fields FieldID="FieldID1" FieldName="Owner" FieldPosition="1" FieldPositionStart="14" FieldLenght="14" FieldEnable="true"/>
                      <Fields FieldID="FieldID2" FieldName="Item" FieldPosition="2" FieldPositionStart="28" FieldLenght="3" FieldEnable="true"/>
                  </Header>
              </Headers>

    Dim ns As XNamespace = "http://tempuri.org/GridLayerSchema.xsd"

    Dim query = (From elmHeader In xml.Root.Elements(ns + "Header")
          Select New Header With {
             .Name = CStr(elmHeader.Element(ns + "Name")),
             .Fields = (From elmField In elmHeader.Elements(ns + "Fields")
                       Select New Field With {
                             .FieldID1 = CStr(elmField.Attribute("FieldID")),
                             .FieldName = CStr(elmField.Attribute("FieldName")),
                             .FieldPosition = CInt(elmField.Attribute("FieldPosition")),
                             .FieldPositionStart = CInt(elmField.Attribute("FieldPositionStart")),
                             .FieldLenght = CInt(elmField.Attribute("FieldLenght")),
                             .FieldEnable = CBool(elmField.Attribute("FieldEnable"))
                           }).ToList()
             }).ToList()
End Sub

Public Class Field
    Public Property FieldID1 As String
    Public Property FieldName As String
    Public Property FieldPosition As Integer
    Public Property FieldPositionStart As Integer
    Public Property FieldLenght As Integer
    Public Property FieldEnable As Boolean
End Class

Public Class Header : Inherits Field 'I think you can drop this inherits but that's up to you
    Public Property Name As String
    Public Property Fields As IEnumerable(Of Field)
End Class

...顺便说一句,如果你在文件的顶部添加一个Imports,你可以用XML文字更多地清理查询。

Imports <xmlns:ns="http://tempuri.org/GridLayerSchema.xsd">

...

Dim query = From elmHeader In xml.Root.<ns:Header>
            Select New Header With {
                    .Name = elmHeader.<ns:Name>.First(),
                    .Fields = From elmField In elmHeader.<ns:Fields>
                            Select New Field With {
                                    .FieldID1 = elmField.@FieldID,
                                    .FieldName = elmField.@FieldName,
                                    .FieldPosition = elmField.@FieldPosition,
                                    .FieldPositionStart = elmField.@FieldPositionStart,
                                    .FieldLenght = elmField.@FieldLenght,
                                    .FieldEnable = elmField.@FieldEnable
                                }
            }