2013-11-08 3 views
4

У меня есть XML, например.Получение XElement через XPathSelectElements

<?xml version="1.0" encoding="utf-8"?> 
    <A1> 
     <B2> 
      <C3 id="1"> 
      <D7> 
       <E5 id="abc" /> 
      </D7> 
      <D4 id="1"> 
       <E5 id="abc" /> 
      </D4> 
      <D4 id="2"> 
       <E5 id="abc" /> 
      </D4> 
      </C3> 
     </B2> 
    </A1> 

Это может образец код:

var xDoc = XDocument.Load("Test.xml"); 
    string xPath = "//B2/C3/D4"; 
    //or string xPath = "//B2/C3/D4[@id='1']"; 

    var eleList = xDoc.XPathSelectElements(xPath).ToList(); 
    foreach (var xElement in eleList) 
    { 
     Console.WriteLine(xElement); 
    } 

Он отлично работает, но если я добавить пространство имен в корневой узел А1, этот код не работает. При поиске решений я нашел this one, но использует метод Descendants() для запроса XML. В моем понимании, это решение потерпит неудачу, если бы я искал <E5>, поскольку тот же тег существует для <D7>, < D4 ID = "1" > и < D4 ID = "2" >

Мое требование для поиска, существует ли узел в определенном XPath. Если есть способ сделать это с помощью потомков, я был бы рад использовать его. Если нет, пожалуйста, расскажите мне, как искать, используя пространство имен.

Приносим извинения, если это дубликат.

ответ

8

Чтобы сохранить с помощью XPath, вы можете использовать что-то ссылку это:

var xDoc = XDocument.Parse(@"<?xml version='1.0' encoding='utf-8'?> 
    <A1 xmlns='urn:sample'> 
     <B2> 
      <C3 id='1'> 
       <D7><E5 id='abc' /></D7> 
       <D4 id='1'><E5 id='abc' /></D4> 
       <D4 id='2'><E5 id='abc' /></D4> 
      </C3> 
     </B2> 
    </A1>"); 

// Notice this 
XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); 
nsmgr.AddNamespace("sample", "urn:sample"); 

string xPath = "//sample:B2/sample:C3/sample:D4"; 

var eleList = xDoc.XPathSelectElements(xPath, nsmgr).ToList(); 
foreach (var xElement in eleList) 
{ 
    Console.WriteLine(xElement); 
} 
+0

Я пробовал это, спасибо, что работает. Это лучший способ сделать это? Я просто спрашиваю, потому что моя функция передается всем XPath как строка, и у нее нет пространства имен, как показано в переменной xPath. Я могу добавить его через замену строки, но просто интересно, есть ли другой способ сделать это? – Charlie

+1

Пространство имен ** префикс ** не имеет значения, просто ** значение ** часть; поэтому, если вы переименуете свой префикс из 'sample' в' whatever', это будет нормально. –

+0

Возможно, у меня что-то отсутствует, я имел в виду, что у вас есть префикс перед каждым именем элемента в переменной xPath. Я просил альтернативу этому. то есть «// sample: B2/sample: C3/sample: D4» – Charlie

2

, но он использует метод Descendants() для запроса XML. По моему мнению, это решение потерпит неудачу, если я буду искать, потому что те же теги существуют, и

Я уверен, что вы не совсем понимаете, как это работает. От MSDN documentation:

Возвращает отфильтрованную коллекцию элементов-потомков для этого документа или элемента в порядке документа. В коллекцию включены только элементы, имеющие соответствующее имя XName.

Так что в вашем случае, просто сделать это:

xDoc.RootNode 
    .Descendants("E5") 
    .Where(n => n.Parent.Name.LocalName == "B4"); 
+0

Да , но как бы я знал, принадлежит ли это моему XPath. Как вы видите, один и тот же узел E5 встречается на нескольких путях. – Charlie

+0

@Charlie, взгляните на мое редактирование. Я использую свойство «Parent», чтобы убедиться, что он является частью элемента «B4». –

+0

это близко, но мой XPath передается как строка, и я не могу динамически проверять каждый родительский узел до корневого узла. Мой XML имеет глубокую иерархию. – Charlie

0

Попробуйте

var xDoc = XDocument.Parse("<A1><B2><C3 id=\"1\"><D7><E5 id=\"abc\" /></D7><D4 id=\"1\"><E5 id=\"abc\" /></D4><D4 id=\"2\"><E5 id=\"abc\" /></D4></C3></B2></A1>"); 
     foreach (XElement item in xDoc.Element("A1").Elements("B2").Elements("C3").Elements("D4")) 
     { 
      Console.WriteLine(item.Element("E5").Value);//to get the value of E5 
      Console.WriteLine(item.Element("E5").Attribute("id").Value);//to get the value of attribute 
     } 
+0

Я не могу этого сделать, я получаю XPath как строку, как мне реализовать это как цикл foreach? Кроме того, XPath может быть на уровне n. Есть ли способ справиться с этим? – Charlie

Смежные вопросы