简体   繁体   English

LINQ to XML将子查询属性选择到字符串列表中

[英]LINQ to XML select subquery attributes into a string list

I'm having some troubles trying to get the needed results from a query and a sub-query list from an XML document. 我在尝试从XML文档的查询和子查询列表中获取所需的结果时遇到了一些麻烦。

I have the following XML document (cut down version) 我有以下XML文档(精简版)

 <ObjectSet ExportMode="Special" Version="1.5.0.2307" Note="TypesFirst"> <MetaInformation> <ExportMode Value="Special" /> <RuntimeVersion Value="1.5.0.2307" /> <SourceVersion Value="1.5.0.2307" /> <ServerFullPath Value="/WW_C27" /> </MetaInformation> <ExportedObjects> <OI NAME="Source Notifications" TYPE="system.base.Folder"> <OI NAME="Joe Blow" TYPE="notification.EmailNotification"> <PI Name="EmailAddress" Value="joeblow@myemail.com" /> <PI Name="EmailSubject" Value="TEST ALARM" /> <PI Name="NotificationText" Value="Alarm text: @(AlarmText) Triggered: @(TimeStamp)" /> <PI Name="Status" Value="1" /> <OI NAME="Filter" TYPE="event.filter.Filter" declared="1" hidden="1"> <OI NAME="AlarmState" TYPE="event.filter.expression.Enum" declared="1"></OI> <OI NAME="Source" TYPE="event.filter.expression.Text" flags="aggregated"> <PI Name="Column" Value="Source" /> <PI Name="DisplayName" Value="Source" /> <OI NAME="Value1" TYPE="event.filter.expression.TextValue" flags="aggregated"> <PI Name="Value" Value="LG Gas Panel Exhaust Fan" /> </OI> <OI NAME="Value3" TYPE="event.filter.expression.TextValue" flags="aggregated"> <PI Name="Value" Value="LG Dewer Alm" /> </OI> </OI> </OI> </OI> <OI NAME="John Smith" TYPE="notification.EmailNotification"> <PI Name="EmailAddress" Value="johnsmith@myemail.com" /> <PI Name="EmailSubject" Value="Work ALARM" /> <PI Name="NotificationText" Value="Alarm text: @(AlarmText) Triggered: @(TimeStamp)" /> <PI Name="Status" Value="1" /> <OI NAME="Filter" TYPE="event.filter.Filter" declared="1" hidden="1"> <OI NAME="AlarmState" TYPE="event.filter.expression.Enum" declared="1"> <PI Name="Column" Value="AlarmState" /> <PI Name="DisplayName" Value="Alarm state" /> <PI Name="EnumType" Value="alarm.pt.AlarmState" /> <OI NAME="1" TYPE="event.filter.expression.EnumValue" flags="aggregated"> <PI Name="Value" Value="1" /> </OI> <OI NAME="0" TYPE="event.filter.expression.EnumValue" flags="aggregated" /></OI> <OI NAME="Source" TYPE="event.filter.expression.Text" flags="aggregated"> <PI Name="Column" Value="Source" /> <PI Name="DisplayName" Value="Source" /> <OI NAME="Value1" TYPE="event.filter.expression.TextValue" flags="aggregated"> <PI Name="Value" Value="Rm 7 FrzAlm" /> </OI> <OI NAME="Value2" TYPE="event.filter.expression.TextValue" flags="aggregated"> <PI Name="Value" Value="Dewer Alm" /> </OI> </OI> </OI> </OI> </OI> </ExportedObjects> </ObjectSet> 

In summary, I need to extract from the above XML document the following details: 总之,我需要从上述XML文档中提取以下详细信息:

  • Person Name 人名
  • Person Email Address 个人电子邮件地址
  • Email Subject 电子邮件主题

All of the above details I'm able to extract and display on my datagrid. 我能够提取并显示在我的数据网格上的所有上述详细信息。

However, for every user there are a number of alarm messages that I need to display in the datagrid, as child rows underneath the datagrid's given user. 但是,对于每个用户,我需要在数据网格中显示许多警报消息,作为数据网格给定用户下方的子行。 I'm not able to do so at the moment. 我目前无法这样做。 What is the best way to achieve the required outcome? 实现所需结果的最佳方法是什么?

From the above XML document, the following is a typical element, that I need to extract as a child list under each user: 从上面的XML文档中,以下是一个典型元素,我需要将其提取为每个用户下的子列表:

 <PI Name="Value" Value="Dewer Alm" /> 

See below my C# code. 请参见下面的C#代码。

List<EmailNotificationClass> NotificationList =
                (
                from n in XDocument.Load(str_XMLFilePath).Root.Descendants("ExportedObjects").Descendants("OI").Descendants("OI")
                where (string)n.Attribute("TYPE") == "notification.EmailNotification"                                       

                let attrib_NAME = n.Attribute("NAME")

                let attrib_EMAIL = n.XPathSelectElement("./PI[@Name='EmailAddress']").Attribute("Value")
                let attrib_SUBJECT = n.XPathSelectElement("./PI[@Name='EmailSubject']").Attribute("Value")
                let attrib_NotificationText = n.XPathSelectElement("./PI[@Name='NotificationText']").Attribute("Value")
                let attrib_Status = n.XPathSelectElement("./PI[@Name='Status']").Attribute("Value")

                let attrib_SourceList = n.XPathSelectElement("//OI/OI[@NAME='Source']/OI/PI[@Name='Value']")



                select new EmailNotificationClass 
                {
                    EN_NotificationName = attrib_NAME.Value,
                    EN_EmailAddress = attrib_EMAIL.Value,
                    EN_EmailSubject = attrib_SUBJECT.Value,
                    EN_NotificationText = attrib_NotificationText.Value,
                    EN_Status = attrib_Status.Value,

                    EN_SourceList = attrib_SourceList.Value //Need to turn this result into a child list
                }
                ).ToList();

            //Set DataGrid source
            DG_Notifications.ItemsSource = NotificationList;

        }
        else
        {
            MessageBox.Show("Please load XML file from the import tab first");
        }            
    }

Any help will be much appreciated. 任何帮助都感激不尽。

Cheers 干杯

Alain 阿兰

Managed to fix the issue myself. 设法自己解决问题。 For anyone that maybe stack with a similar problem, the issue was the way I defined the class that holds the data, which later will be displayed in the DataGrid. 对于可能会遇到类似问题的任何人,问题在于我定义了保存数据的类的方式,该类随后将显示在DataGrid中。

Once I changed the string Sources within the first class to a List, I was able to retrieve the list of alarms per person. 将第一个类中的字符串Sources更改为List后,我便能够检索到每个人的警报列表。

    public class EmailNotificationClass
{
    //EN = EmailNotification OI in the XML document       
    public string EN_NotificationName { get; set; }
    public string EN_EmailAddress { get; set; }
    public string EN_EmailSubject { get; set; }
    public string EN_NotificationText { get; set; }
    public string EN_Status { get; set; }
    public string EN_FilterType { get; set; }
    public List<EN_F_SourceClass> Sources { get; set; }

}


public class EN_F_SourceClass
{
    public string FilterSource { get; set; }
}

I then modified the code behind as followed 然后,我修改了后面的代码,如下所示

List<EmailNotificationClass> NotificationList =
                (

                from n in XDocument.Load(str_XMLFilePath).Root.Descendants("ExportedObjects").Descendants("OI").Descendants("OI")
                where (string)n.Attribute("TYPE") == "notification.EmailNotification"                                       

                let attrib_NAME = n.Attribute("NAME")

                let attrib_EMAIL = n.XPathSelectElement("./PI[@Name='EmailAddress']").Attribute("Value")
                let attrib_SUBJECT = n.XPathSelectElement("./PI[@Name='EmailSubject']").Attribute("Value")
                let attrib_NotificationText = n.XPathSelectElement("./PI[@Name='NotificationText']").Attribute("Value")
                let attrib_Status = n.XPathSelectElement("./PI[@Name='Status']").Attribute("Value")


                select new EmailNotificationClass
                {
                    EN_NotificationName = attrib_NAME.Value,
                    EN_EmailAddress = attrib_EMAIL.Value,
                    EN_EmailSubject = attrib_SUBJECT.Value,
                    EN_NotificationText = attrib_NotificationText.Value,
                    EN_Status = attrib_Status.Value,

                    Sources = 
                    (
                    from source in n.XPathSelectElements("OI/OI[@NAME='Source']/OI/PI[@Name='Value']")
                    select new EN_F_SourceClass
                    {
                        FilterSource = (string)source.Attribute("Value")
                    }).ToList()

                }
                ).ToList();


            //Set DataGrid source
            DG_Notifications.ItemsSource = NotificationList;

        }
        else
        {
            MessageBox.Show("Please load XML file from the import tab first");
        }            

The xalm part was easy. xalm部分很简单。 Just added a RowDeetailsTemplate as follow 刚刚添加了RowDeetailsTemplate如下

 <DataGrid.RowDetailsTemplate> <DataTemplate> <Grid MaxHeight="100"> <ScrollViewer> <Border BorderThickness="0" Background="#FFB8E8A1" Padding="5"> <DataGrid ItemsSource="{Binding Sources}" IsReadOnly="True" SelectionMode="Single" SelectionUnit="FullRow" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Width="400" Header="Alarms" Binding="{Binding FilterSource}"></DataGridTextColumn> </DataGrid.Columns> </DataGrid> </Border> </ScrollViewer> </Grid> </DataTemplate> </DataGrid.RowDetailsTemplate> 

Thanks for reading, 谢谢阅读,

Alain 阿兰

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM