2011-02-07 13 views
6

Estoy usando XPath para excluir ciertos nodos dentro de un menú. Quiero ampliar esto para excluir los nodos identificados dentro de una matriz.¿Cómo hago referencia a valores de matriz dentro de string.Format?

Esto funciona para excluir todos los nodos en el menú con id 2905 cuyo tipo no es contenido:

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

Lo que me gustaría es almacenar la MenuID y varios otros en una matriz y después hacer referencia a que matriz dentro de la función string.Format

Algo así como:

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

Cualquier consejo sería muy apreciada!

ta Nathan

Editar - incluyen ejemplo 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

Buena pregunta, +1. Vea mi respuesta para una solución completa y fácil. :) –

+0

Compruebe mi respuesta para una clásica expresión "existe en secuencia" XPath 1.0. –

Respuesta

1

Uso:

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

Ten en cuenta: En el código anterior de las cuerdas se han dividido en diferentes líneas para mejorar la legibilidad. En el código ypur no debe dividir ninguna cadena, ni usar el operador de cadena + (concatenación) para lograr el mismo efecto.

+3

Recomiendo también usar un StringBuilder y AppendFormat. – Foole

+0

Ok, veo exactamente lo que estás haciendo, iterando a través de la matriz y usando esa información para crear la cadena que se usa en NodeList. Obtengo un error de compilación al usar Count: intenté cambiar eso para usar Length, sin error, pero sin salida. ¿Algunas ideas? – Nathan

+0

@Nathan: Sí, es 'Longitud'. En cuanto a "sin salida", ¿puede imprimir la expresión XPath final y proporcionarla para que podamos ver qué está sucediendo? –

0

No estoy 100% seguro de qué nodos espera aquí, pero en función de lo que intentó escribir, traté de replicar de una manera escalable.

Básicamente, tendrá que usar los contenidos de la matriz para construir el XPath correcto. Aquí tengo algunas funciones para ayudar a cambiar estas listas de exclusión en la condición XPath apropiada. Personalmente, me parece que el uso de LINQ y string.Join() hace esto mucho más fácil de escribir y administrar.

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

Recuerde que siempre puede utilizar este tipo de XPath 1.0 expresión por la existencia de pruebas en secuencia:

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

Gracias a todos por los consejos - Me voy como una expresión XPath simples por ahora , tiene cosas más importantes que hacer. Las posibilidades de querer excluir más submenús son razonablemente delgada, y voy a tratar con ellos a medida que surgen ...

estoy usando el siguiente como mi solución -

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

es una muy ordinaria xml doc para empezar, pesa 12.5 mb, y para ser honesto, prefiero trabajar en otras áreas del sitio ...

0

En primer lugar, no necesita una expresión "in". El operador = significa automáticamente "si coincide con algo en la secuencia".

En cuanto a su pregunta real, si es posible reificar la expresión xpath como un tipo de objeto y vincular variables, entonces probablemente sea fácil de hacer.No estoy familiarizado con C++ en partiucular, pero yo esperaría a ver algo vagamente a

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

muy parecido a la utilización de variables en una sentencia SQL preparada.

Cuestiones relacionadas