如何在string.Format中引用数组值?

时间:2011-02-07 01:03:57

标签: c# .net xml xslt xpath

我正在使用XPath来排除菜单中的某些节点。我想对此进行扩展,以排除在数组中标识的节点。

这可以排除菜单中所有节点,其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));

我想要的是将menuId和其他几个存储在一个数组中,然后在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>

5 个答案:

答案 0 :(得分: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代码中,您不能拆分任何字符串,或使用字符串+(连接)运算符来实现相同的效果。

答案 1 :(得分: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);

答案 2 :(得分:0)

请记住,您始终可以使用此类XPath 1.0表达式按顺序测试存在:

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

答案 3 :(得分: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 MB,说实话,我宁愿在网站的其他区域工作....

答案 4 :(得分:0)

首先,您不需要“in”表达式。 =运算符自动表示“如果它匹配序列中的任何内容。”

至于你真正的问题,如果可以将xpath表达式作为某种对象和绑定变量来实现,那么它可能很容易实现。我对partiucular中的c ++并不熟悉,但我希望看到一些模糊的东西

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

非常像在sql准备语句中使用变量。