我正在使用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>
答案 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准备语句中使用变量。