2012-02-01 50 views
4

這裏是我的XML文件:獲取的XElement的XML

<Applications> 
    <Application Name="Abc"> 
    <Section Name="xyz"> 
     <Template Name="hello"> 
     ... 
     .... 
     </Template> 
     </Section> 
    </Application> 
    <Application Name="Abc1"> 
    <Section Name="xyz1"> 
     <Template Name="hello"> 
     ... 
     .... 
     </Template> 
     </Section> 
    </Application> 

我需要做的是從基於模板標籤的名稱屬性指定的結構得到了模板的XElement。問題是可以有多個具有相同屬性名稱的模板標籤。區分因素是應用程序名稱屬性值和節屬性值。

目前我能夠通過首先獲取基於它的屬性的應用程序元素,然後基於它的屬性,然後最終基於它的名稱模板來獲得XElement。

我想知道是否有辦法一氣呵成。

+0

你或許可以通過建立和評估XPath表達式,但使用LINQ to XML和目前的做法也是有效的,高效的戰略實現這一目標。爲什麼要匹配元素「一氣呵成」是否有特殊原因? – 2012-02-01 13:26:52

+0

沒有特別的原因,只是想知道是否有可能實現它。 – gizgok 2012-02-01 13:51:30

回答

1

下面的代碼應該做的伎倆:

var template = doc.Descendants("Template") 
        .Where(x => x.Attribute("Name").Value == "hello" 
          && x.Parent.Attribute("Name").Value == "xyz1" 
          && x.Parent.Parent.Attribute("Name").Value == "Abc1"); 

請注意,此代碼引發異常,如果XML不符合規範。具體而言,如果有問題的任何標籤不包含名爲「Name」的屬性,則會有NullReferenceException。或者如果模板標籤沒有父母的兩個級別。

+0

像魅力一樣工作,在最後添加FirstOrDefault()。 – gizgok 2012-02-01 13:50:21

1
XDocument doc = XDocument.Load("Path of xml"); 
    var selection = 
     doc.Descendants("Section").Select(item => item).Where(
      item => item.Attribute("Name").Value.ToString().Equals("Section Name Value")).ToList(); 

    if(null != selection) 
    { 
     var template = 
      selection.Descendants("Template").Select(item => item).Where(
      item => item.Attribute("Name").Value.ToString().Equals("Template name value")); 
    } 
+0

我還沒有試過你的答案,我會一旦回來就會回來。 – gizgok 2012-02-01 13:50:37

6

我會用事實,你可以調用Elements或現有的序列,因此:

var template = doc.Descendants("Application") 
        .Where(x => (string) x.Attribute("Name") == applicationName) 
        .Elements("Section") 
        .Where(x => (string) x.Attribute("Name") == sectionName) 
        .Elements("Template") 
        .Where(x => (string) x.Attribute("Name") == templateName) 
        .FirstOrDefault(); 

你甚至可能要添加的地方擴展方法:

public static IEnumerable<XElement> WithName(this IEnumerable<XElement> elements, 
              string name) 
{ 
    this elements.Where(x => (string) x.Attribute("Name") == name); 
} 

然後你可以重寫查詢爲:

var template = doc.Descendants("Application").WithName(applicationName) 
        .Elements("Section").WithName(sectionName) 
        .Elements("Template").WithName(templateName) 
        .FirstOrDefault(); 

......我認爲你會同意的是readab樂:)

注意,在使用鑄造XAttributestring,而不是使用Value財產意味着沒有Name屬性的任何元素都只是有效地忽略,而不是造成NullReferenceException

+0

整潔和+1的擴展方法,並沒有意識到這一點。謝謝 – gizgok 2012-02-01 13:54:22

1

XPath應該可以幫到你。使用Extensions.XPathSelectElement Method (XNode, String)

XDocument xdoc = XDocument.Load("yourfile.xml"); 
string xPathQuery = string.Format(
    "/Applications/Application[@Name='{0}']/Section[@Name='{1}']/Template[@Name='{2}']", 
    "MyApplication", 
    "MySection", 
    "MyTemplate" 
); 

XElement template = xdoc.Root.XPathSelectElement(xPathQuery); 
+0

由於節點層次是已知的,我寧願去與** xDoc.XPathSelectElements(「/應用程序/應用程序/部分/模板[@名稱='」+ templateName +「']」); **應該是更高效 – nulltoken 2012-02-01 13:39:40

+0

@nulltoken:這不尊重OP​​的要求。 – 2012-02-01 13:45:06

+0

@DanielHilgarth你說得對。我*已*忘記爲* Application *和* Section *添加命名的限制。我的意思是寧願使用根的顯式路徑,而不是「// template [@ Name ='xxxx']」查詢。但是,它看起來像答案已經修復:) – nulltoken 2012-02-01 13:53:46