2011-02-07 130 views
6

我正在使用XPath排除菜單中的某些節點。我想對此進行擴展以排除在數組中標識的節點。如何在string.Format內引用數組值?

這可以用來排除菜單中的所有節點ID爲2905,其類型不是內容:

XmlNodeList nextLevelNodeList = currentNode 
            .SelectNodes(string 
                .Format(" 
              Menu[not(MenuId = 2905)] 
               /Item[ 
               ItemLevel = {0} 
                and 
               ItemType != 'Javascript' 
               ] | 
              Menu[MenuId = 2905] 
               /Item[ 
               ItemLevel = {0} 
                and 
               ItemType = 'content' 
               ]", iLevel)); 

我想什麼是對菜單Id和其他幾個人存放在數組,然後引用該功能的String.format

喜歡的東西中數組:

int[] excludeSubmenus = {2905, 323}; 
XmlNodeList nextLevelNodeList = currentNode 
            .SelectNodes(string 
                .Format(" 
             Menu[not(MenuId in excludesubMenus)] 
              /Item[ 
               ItemLevel={0} 
                and 
               ItemType != 'Javascript' 
              ] | 
             Menu[MenuId in excludeSubMenus] 
              /Item[ 
               ItemLevel={0} 
                and 
               ItemType='content' 
              ]", iLevel)); 

任何意見將不勝感激!

TA 彌敦道

編輯 - 包括示例XML

<Item> 
    <ItemId>322</ItemId> 
    <ItemType>Submenu</ItemType> 
    <ItemLevel>2</ItemLevel> 
    <Menu> 
     <MenuId>322</MenuId> 
     <MenuLevel>2</MenuLevel> 
     <Item> 
      <ItemId>2905</ItemId> 
      <ItemType>Submenu</ItemType> 
      <ItemLevel>3</ItemLevel> 
      <Menu> 
       <MenuId>2905</MenuId> 
       <MenuLevel>3</MenuLevel> 
       <Item> 
        <ItemId>19196</ItemId> 
        <ItemType>content</ItemType> 
        <ItemLevel>4</ItemLevel> 
       </Item> 
       <Item> 
        <ItemId>19192</ItemId> 
        <ItemType>Submenu</ItemType> 
        <ItemLevel>4</ItemLevel> 
       </Item> 
      </Menu> 
     </Item> 
     <Item> 
      <ItemId>2906</ItemId> 
      <ItemType>Submenu</ItemType> 
      <ItemLevel>3</ItemLevel> 
      <Menu> 
       <MenuId>323</MenuId> 
       <MenuLevel>3</MenuLevel> 
       <Item> 
        <ItemId>2432</ItemId> 
        <ItemType>content</ItemType> 
        <ItemLevel>4</ItemLevel> 
       </Item> 
       <Item> 
        <ItemId>12353</ItemId> 
        <ItemType>Submenu</ItemType> 
        <ItemLevel>4</ItemLevel> 
       </Item> 
      </Menu> 
     </Item> 
    </Menu> 
</Item> 
+0

好問題,+1。查看我的答案,獲得完整而簡單的解決方案。 :) – 2011-02-07 01:27:05

+0

請檢查我的答案是否有經典的「存在序列」XPath 1.0表達式。 – 2011-02-07 15:38:40

回答

1

使用

int[] excludeSubmenus = {2905, 323}; 

string notExpr = string.Empty; 

for(int i=0; i < excludeSubmenus.Length; i++) 
    { 
    notExpr += string.Format("not(MenuId={0})", excludeSubmenus[i]); 

    if(i != excludeSubmenus.Count-1) 
     notExpr += " and "; 
    } 

XmlNodeList nextLevelNodeList = 
    currentNode.SelectNodes(
     string.Format("//Menu[MenuId in excludeSubMenus]/Item 
           [ItemLevel={1} and not(ItemType='Javascript')]", 
         notExpr, iLevel) 
        ); 

請注意:在上面的代碼串被分成不同的以增強可讀性。在ypur代碼中,您不能拆分任何字符串,或者使用字符串+(拼接)運算符來實現相同的效果。

0

我不是100%肯定你想到這裏,但根據你試着寫什麼,我想在一個可擴展的方式來複制哪些節點。

基本上你將不得不使用數組的內容建立正確的XPath。這裏我有一些功能可以幫助將這些排除列表更改爲適當的XPath條件。就我個人而言,我發現使用LINQ和string.Join()可以更容易地編寫和管理。

// supporting methods to build parts of the string 
static string ElementNotInList<T>(string element, params T[] list) 
{ 
    return String.Join(" and ", list.Select(x => String.Concat(element, "!=", x))); 
} 
static string ElementInList<T>(string element, params T[] list) 
{ 
    return String.Join(" or ", list.Select(x => String.Concat(element, "=", x))); 
} 


var excludeSubmenus = new[] { 2905, 323 }; 
var xpath = String.Join("|", 
    String.Format("//Menu[{0}]/Item[ItemLevel={1} and ItemType!='Javascript']", 
     ElementNotInList("MenuId", excludeSubmenus), iLevel), 
    String.Format("//Menu[{0}]/Item[ItemLevel={1} and ItemType='content']", 
     ElementInList("MenuId", excludeSubmenus), iLevel) 
); 
var nextLevelNodeList = currentNode.SelectNodes(xpath); 
0

請記住,你總是可以按順序使用這種的XPath 1.0表達式的測試存在:

Menu/Item[ 
    contains(
     concat(' ','2905 323',' '), 
     concat(' ',../MenuId,' ') 
    ) and 
    ItemType = 'content' 
    or 
    ItemType != 'Javascript' 
][ 
    ItemLevel = {0} 
] 
0

感謝所有的意見 - 我把它當作一個簡單的XPath表達式現在,有更重要的事情要做。想要的機會,排除更多的子菜單是相當渺茫,當他們出現,我會對付他們......

我使用的是下面是我的解決方案 -

 XmlNodeList nextLevelNodeList = currentNode.SelectNodes(string.Format("Menu[not(MenuId = 2905) and not(MenuId = 323)]/Item[ItemLevel={0} and ItemType != 'Javascript'] | Menu[MenuId = 2905 or MenuId = 323]/Item[ItemLevel={0} and ItemType='content']", iLevel)); 

這是一個非常普通的XML文檔入手,重量在12.5萬桶,並說實話,我寧願被工作首先在網站的其他領域....

0

,你並不需要一個「在」表達。 =運算符自動錶示「如果它與序列中的任何內容匹配」。

至於你真正的問題,如果有可能,以具體化XPath表達式作爲某種對象和綁定變量,那麼它可能容易做到。我不熟悉C++中partiucular,但是我希望看到的東西隱約像

 
XPathExpr foo = XPathExpr("/Item[not(type=$badType)]");` 
foo.bind("badType", toXpathSquence(the_bad_types));` 
foo.eval(the_xml_to_evaluate);` 

很像在SQL預處理語句使用變量。