How to bind array values ​​in string.Format?

I use XPath to exclude certain nodes in the menu. I want to expand this to exclude nodes identified inside the array.

This allows you to exclude all nodes in the menu with identifier 2905, the type of which is not content:

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)); 

I would like to save menuId and several others in an array, and then reference that array inside string.Format function

Something like:

 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)); 

Any advice would be greatly appreciated!

Ta Nathan

Edit - enable xml example

 <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> 
+6
c # xml xpath xslt
source share
5 answers

Using

 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) ); 

Pay attention . In the above code, the lines were split into different lines to increase readability. In ypur code, you should not split any line or use the + (concatenation) operator to achieve the same effect.

+1
source share

I am not 100% sure which nodes you expect here, but based on what you tried to write, I tried to replicate in a scalable way.

Basically you will need to use the contents of the array to create the correct XPath. Here I have some functions that will help change these exception lists into the corresponding XPath condition. Personally, I use LINQ and string.Join() to make this a lot easier to write and manage.

 // 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
source share

Remember that you can always use this kind of XPath 1.0 expression to test existence in a sequence:

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

Thanks to everyone for the advice - I leave this as a simple xpath expression for now, there are more important things to do. The chances of wanting to exclude more submenus are rather thin, and I will solve them as they arise ...

I use below as my solution -

  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)); 

This is a pretty ordinary xml document to begin with, it weighs 12.5 mb, and to be honest, I would prefer to work in other areas of the site ....

0
source share

First, you do not need the expression "in". The = operator automatically means "if it matches anything in the sequence."

As for your real question, if it's possible to validate an xpath expression as a kind of object and binding variables, then this is probably easy to do. I am not familiar with C ++ in partyucular, but I would expect to see something unclear how

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

very similar to using variables in a prepared SQL query.

0
source share

All Articles