Как я могу ссылаться на значения массива в string.Format? - PullRequest
6 голосов
/ 07 февраля 2011

Я использую XPath для исключения определенных узлов в меню. Я хочу расширить это, чтобы исключить узлы, идентифицированные в массиве.

Это работает для исключения всех узлов в меню с идентификатором 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 и несколько других в массиве, а затем ссылаться на этот массив в строке. Функция формата

Что-то вроде:

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

Любой совет будет принята с благодарностью!

та Nathan

Изменить - включить пример 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 ]

1 голос
/ 07 февраля 2011

Используйте

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 голосов
/ 16 февраля 2011

Во-первых, вам не нужно выражение "in". Оператор = автоматически означает «если он соответствует чему-либо в последовательности».

Что касается вашего реального вопроса, если возможно преобразовать выражение xpath как некоторый объект и связать переменные, то, вероятно, это легко сделать. Я не знаком с C ++ в частности, но я ожидаю увидеть что-то смутное, как

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

очень похоже на использование переменных в подготовленном SQL-выражении.

0 голосов
/ 08 февраля 2011

Спасибо всем за совет - пока я оставляю это как простое выражение 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 голосов
/ 07 февраля 2011

Помните, что вы всегда можете использовать этот вид выражения XPath 1.0 для проверки существования в последовательности:

Menu/Item[
   contains(
      concat(' ','2905 323',' '),
      concat(' ',../MenuId,' ')
   ) and
   ItemType = 'content'
     or
   ItemType != 'Javascript'
][
   ItemLevel = {0}
]
0 голосов
/ 07 февраля 2011

Я не уверен на 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...