LINQ to XML 和独特的自定义类

发布于 2024-08-08 00:14:43 字数 1636 浏览 4 评论 0原文

我有一个非常有趣的 LINQ 问题。我有一个文档,我正在尝试过滤结果,但为了过滤,我匹配来自 XML 一个元素的 REGEX 结果。

我有以下内容,使用 LINQ to XML 来获取我正在查找的单个数据。

Dim oDocument As XDocument
oDocument = XDocument.Load("test.xml")
Dim results = (From x In oDocument.Descendants.Elements("ROW") _
   Select New With {.ApplicationName = GetApplicationName(x.Element("Message")), _
    .EventId = x.Element("EventId")}).Distinct

但是,.Distinct 并没有达到我想要的效果,它仍然显示“ApplicationName”和“EventId”的所有组合。

我最终需要的是一个不同的结果列表,位于一个新对象中,其中包含应用程序名称和 XML 中的事件 ID。

“GetAPplicationName”是一个解析值以查找正则表达式匹配的函数。

有什么指点吗?

示例 XML

<ROOT>
  <ROW>
    <EventId>1</EventId>
    <CreatedTimestamp>2009-10-28</CreatedTimestamp>
    <Message>There is a bunch
    of 
  garbled
inforamtion here and I'm trying to parse out a value 
Virtual Path: /MyPath then it continues on with more junk after the
message, including extra stuff
    </Message>
    <!--Other elements removed for brevity -->
  </ROW>
  <ROW>
    <EventId>1</EventId>
    <CreatedTimestamp>2009-10-28</CreatedTimestamp>
    <Message>
      There is a bunch
      of
      garbled
      inforamtion here and I'm trying to parse out a value
      Virtual Path: /MyPath then it continues on with more junk after the
      message, including extra stuff
    </Message>
    <!--Other elements removed for brevity -->
  </ROW>
</ROOT>

从这里我想要不同的 /MyPath 和 EventId(在本例中,1 个条目带有 /MyPath 和 1.My

GetApplicationNameMethod,在此示例中将返回 /MyPath

I have a very interesting LINQ question. I have a document, that I am trying to filter results on, but to filter, I am matching on a REGEX result from one element of the XML.

I have the following, working LINQ to XML to get the individual data that I'm looking for.

Dim oDocument As XDocument
oDocument = XDocument.Load("test.xml")
Dim results = (From x In oDocument.Descendants.Elements("ROW") _
   Select New With {.ApplicationName = GetApplicationName(x.Element("Message")), _
    .EventId = x.Element("EventId")}).Distinct

However, the .Distinct doesn't do what I want, it still shows all combinations of "ApplicationName" and "EventId".

What I need in the end is a distinct list of results, in a new object with the application name, and event id from the XML.

The "GetAPplicationName" is a function that parses the value looking for a regex match.

Any pointers?

Sample XML

<ROOT>
  <ROW>
    <EventId>1</EventId>
    <CreatedTimestamp>2009-10-28</CreatedTimestamp>
    <Message>There is a bunch
    of 
  garbled
inforamtion here and I'm trying to parse out a value 
Virtual Path: /MyPath then it continues on with more junk after the
message, including extra stuff
    </Message>
    <!--Other elements removed for brevity -->
  </ROW>
  <ROW>
    <EventId>1</EventId>
    <CreatedTimestamp>2009-10-28</CreatedTimestamp>
    <Message>
      There is a bunch
      of
      garbled
      inforamtion here and I'm trying to parse out a value
      Virtual Path: /MyPath then it continues on with more junk after the
      message, including extra stuff
    </Message>
    <!--Other elements removed for brevity -->
  </ROW>
</ROOT>

From here I want the distinct /MyPath and EventId (In this case 1 entry with /MyPath and 1.

My GetApplicationNameMethod, on this sample will return /MyPath

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

山川志 2024-08-15 00:14:43

艾哈迈德的回答是正确的,我投了赞成票。不过,我只是想指出 LINQ to XML 查询的替代 VB.NET 特定语法。

Dim results = From x In doc...<ROW> _
   Select New EventInfo With {.ApplicationName = GetApplicationName(x.<Message>.Value, _
    .EventId = x.<EventId>.Value}

这会返回相同的结果,但如果您导入 xmlns,那么您将通过这种方式获得元素名称的 IntelliSense。

以下文章介绍了如何在 VB.NET 中获取 XML IntelliSense:

http:// msdn.microsoft.com/en-us/library/bb531325.aspx

Ahmad's answer is correct and I upvoted it. However, I just wanted to point out the alternative VB.NET specific syntax for your LINQ to XML query.

Dim results = From x In doc...<ROW> _
   Select New EventInfo With {.ApplicationName = GetApplicationName(x.<Message>.Value, _
    .EventId = x.<EventId>.Value}

This returns the same result, but if you import an xmlns, then you'll get IntelliSense for the element names this way.

Here's an article describing how to get XML IntelliSense in VB.NET:

http://msdn.microsoft.com/en-us/library/bb531325.aspx

天邊彩虹 2024-08-15 00:14:43

Distinct 不知道如何比较您的项目,因此它返回所有未过滤的项目。您应该使用实现 IEqualityComparer 的独特重载。这将允许您比较 ApplicationName 和 EventId 属性以确定相等性。然而,这样做意味着拥有一个真正的类,而不是一个匿名类型。该文档演示了如何以易于理解的方式实现这一目标。

编辑:我能够将您的示例与 IEqualityComparer 和 EventInfo 类一起使用。我添加了自己的 GetApplicationName 实现来测试。

    Dim results = (From x In doc.Descendants.Elements("ROW") _
       Select New EventInfo With {.ApplicationName = GetApplicationName(x.Element("Message")), _
        .EventId = x.Element("EventId")})

    Console.WriteLine("Total: {0}", results.Count)
    Console.WriteLine("Distinct Total: {0}", results.Distinct.Count)
    Console.WriteLine("Distinct (w/comparer) Total: {0}", results.Distinct(New EventInfoComparer()).Count)

输出:

Total: 2
Distinct Total: 2
Distinct (w/comparer) Total: 1

其余代码:

' EventInfo class and comparer
Private Function GetApplicationName(ByVal element As XElement)
    Return Regex.Match(element.Value, "Virtual\sPath:\s/(\w+)").Groups(1).Value
End Function

Public Class EventInfo
    Private _applicationName As String
    Public Property ApplicationName() As String
        Get
            Return _applicationName
        End Get
        Set(ByVal value As String)
            _applicationName = value
        End Set
    End Property

    Private _eventId As Integer
    Public Property EventId() As Integer
        Get
            Return _eventId
        End Get
        Set(ByVal value As Integer)
            _eventId = value
        End Set
    End Property
End Class

Public Class EventInfoComparer
    Implements IEqualityComparer(Of EventInfo)

    Public Function Equals1(ByVal x As EventInfo, ByVal y As EventInfo) As Boolean _
        Implements IEqualityComparer(Of EventInfo).Equals

        ' Check whether the compared objects reference the same data.
        If x Is y Then Return True

        ' Check whether any of the compared objects is null.
        If x Is Nothing OrElse y Is Nothing Then Return False

        ' Check whether the EventInfos' properties are equal.
        Return (x.ApplicationName = y.ApplicationName) AndAlso (x.EventId = y.EventId)
    End Function

    Public Function GetHashCode1(ByVal eventInfo As EventInfo) As Integer _
        Implements IEqualityComparer(Of EventInfo).GetHashCode

        ' Check whether the object is null.
        If eventInfo Is Nothing Then Return 0

        ' Get the hash code for the ApplicationName field if it is not null.
        Dim hashEventInfoAppName = _
            If(eventInfo.ApplicationName Is Nothing, 0, eventInfo.ApplicationName.GetHashCode())

        ' Get the hash code for the EventId field.
        Dim hashEventInfoId = eventInfo.EventId.GetHashCode()

        ' Calculate the hash code for the EventInfo.
        Return hashEventInfoAppName Xor hashEventInfoId
    End Function
End Class

Distinct doesn't know how to compare your items, so it returns all the items unfiltered. You should use the Distinct overload that implements IEqualityComparer. This would allow you to compare the ApplicationName and EventId properties to determine equality. However, doing so would mean having a real class, not an anonymous type. The documentation demonstrates how to achieve this in an easy to understand manner.

EDIT: I was able to use your sample with the IEqualityComparer and an EventInfo class. I added my own implementation of GetApplicationName to test.

    Dim results = (From x In doc.Descendants.Elements("ROW") _
       Select New EventInfo With {.ApplicationName = GetApplicationName(x.Element("Message")), _
        .EventId = x.Element("EventId")})

    Console.WriteLine("Total: {0}", results.Count)
    Console.WriteLine("Distinct Total: {0}", results.Distinct.Count)
    Console.WriteLine("Distinct (w/comparer) Total: {0}", results.Distinct(New EventInfoComparer()).Count)

This outputs:

Total: 2
Distinct Total: 2
Distinct (w/comparer) Total: 1

The rest of the code:

' EventInfo class and comparer
Private Function GetApplicationName(ByVal element As XElement)
    Return Regex.Match(element.Value, "Virtual\sPath:\s/(\w+)").Groups(1).Value
End Function

Public Class EventInfo
    Private _applicationName As String
    Public Property ApplicationName() As String
        Get
            Return _applicationName
        End Get
        Set(ByVal value As String)
            _applicationName = value
        End Set
    End Property

    Private _eventId As Integer
    Public Property EventId() As Integer
        Get
            Return _eventId
        End Get
        Set(ByVal value As Integer)
            _eventId = value
        End Set
    End Property
End Class

Public Class EventInfoComparer
    Implements IEqualityComparer(Of EventInfo)

    Public Function Equals1(ByVal x As EventInfo, ByVal y As EventInfo) As Boolean _
        Implements IEqualityComparer(Of EventInfo).Equals

        ' Check whether the compared objects reference the same data.
        If x Is y Then Return True

        ' Check whether any of the compared objects is null.
        If x Is Nothing OrElse y Is Nothing Then Return False

        ' Check whether the EventInfos' properties are equal.
        Return (x.ApplicationName = y.ApplicationName) AndAlso (x.EventId = y.EventId)
    End Function

    Public Function GetHashCode1(ByVal eventInfo As EventInfo) As Integer _
        Implements IEqualityComparer(Of EventInfo).GetHashCode

        ' Check whether the object is null.
        If eventInfo Is Nothing Then Return 0

        ' Get the hash code for the ApplicationName field if it is not null.
        Dim hashEventInfoAppName = _
            If(eventInfo.ApplicationName Is Nothing, 0, eventInfo.ApplicationName.GetHashCode())

        ' Get the hash code for the EventId field.
        Dim hashEventInfoId = eventInfo.EventId.GetHashCode()

        ' Calculate the hash code for the EventInfo.
        Return hashEventInfoAppName Xor hashEventInfoId
    End Function
End Class
汹涌人海 2024-08-15 00:14:43

我以前从未注意到这一点,但 VB 的匿名类型似乎不会覆盖 Equals()GetHashcode()。因此,Distinct() 正在检查引用相等性。最简单的解决方法是构建您自己的实现 IEquatable 的类。

I had never noticed this before, but it seems VB's anonymous types do not override Equals() and GetHashcode(). As such, Distinct() is checking reference equality. The easiest workaround is to build your own class that implements IEquatable<T>.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文