Примером этого исключаемого исключения является: Когда вы пытаетесь проверить что-то, это null.
Например:
string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)
if (testString.Length == 0) // Throws a nullreferenceexception
{
//Do something
}
Время выполнения .NET исключение NullReferenceException при попытке выполнить действие над чем-то, что не было инстанцировано, т.е. код выше.
По сравнению с ArgumentNullException, которое обычно выбрано как защитная мера, если метод ожидает, что то, что происходит
Дополнительная информация находится в C # NullReferenceException и Null Parameter .
Сначала вам не нужен навигатор; SelectNodes / SelectSingleNode должен быть достаточным.
Однако вам может понадобиться менеджер пространства имен - например:
XmlElement el = ...; //TODO
XmlNamespaceManager nsmgr = new XmlNamespaceManager(
el.OwnerDocument.NameTable);
nsmgr.AddNamespace("x", el.OwnerDocument.DocumentElement.NamespaceURI);
var nodes = el.SelectNodes(@"/x:outerelement/x:innerelement", nsmgr);
Возможно, вы захотите попробовать инструмент XPath Visualizer, чтобы помочь вам.
XPathVisualizer является бесплатным, простым в использовании.
ВАЖНО: Если вы используете Windows 7/8 и не видите пункты меню «Файл», «Редактировать» и «Справка», нажмите клавишу ALT.
Вы можете использовать инструкцию XPath без использования XmlNamespaceManager следующим образом:
...
navigator.Select("//*[ local-name() = 'innerelement' and namespace-uri() = '' ]")
...
Это простой способ выбора элемента в XML с определением пространства имен по умолчанию. Дело в том, чтобы использовать:
namespace-uri() = ''
, который найдет элемент с пространством имен по умолчанию без использования префиксов.
Я столкнулся с аналогичной проблемой с пустым пространством имен по умолчанию. В этом примере XML у меня есть сочетание элементов с префиксами пространства имен и один элемент (DataBlock) без:
<src:SRCExample xmlns="urn:some:stuff:here" xmlns:src="www.test.com/src" xmlns:a="www.test.com/a" xmlns:b="www.test.com/b">
<DataBlock>
<a:DocID>
<a:IdID>7</a:IdID>
</a:DocID>
<b:Supplimental>
<b:Data1>Value</b:Data1>
<b:Data2/>
<b:Extra1>
<b:More1>Value</b:More1>
</b:Extra1>
</b:Supplimental>
</DataBlock>
</src:SRCExample>
Я попытался использовать XPath, который работал в XPath Visualizer, но не работал в моем коде:
XmlDocument doc = new XmlDocument();
doc.Load( textBox1.Text );
XPathNavigator nav = doc.DocumentElement.CreateNavigator();
XmlNamespaceManager nsman = new XmlNamespaceManager( nav.NameTable );
foreach ( KeyValuePair<string, string> nskvp in nav.GetNamespacesInScope( XmlNamespaceScope.All ) ) {
nsman.AddNamespace( nskvp.Key, nskvp.Value );
}
XPathNodeIterator nodes;
XPathExpression failingexpr = XPathExpression.Compile( "/src:SRCExample/DataBlock/a:DocID/a:IdID" );
failingexpr.SetContext( nsman );
nodes = nav.Select( failingexpr );
while ( nodes.MoveNext() ) {
string testvalue = nodes.Current.Value;
}
Я сузил его до элемента «DataBlock» XPath, но не смог заставить его работать, за исключением простого подстановки элемента DataBlock:
XPathExpression workingexpr = XPathExpression.Compile( "/src:SRCExample/*/a:DocID/a:IdID" );
failingexpr.SetContext( nsman );
nodes = nav.Select( failingexpr );
while ( nodes.MoveNext() ) {
string testvalue = nodes.Current.Value;
}
После того, как я много раз набрал чек и Google (я приземлился здесь), я решил заняться пространством имен по умолчанию непосредственно в моем загрузчике XmlNamespaceManager, изменив его на:
foreach ( KeyValuePair<string, string> nskvp in nav.GetNamespacesInScope( XmlNamespaceScope.All ) ) {
nsman.AddNamespace( nskvp.Key, nskvp.Value );
if ( nskvp.Key == "" ) {
nsman.AddNamespace( "default", nskvp.Value );
}
}
Итак, теперь точка «по умолчанию» и «» к тому же пространству имен. Как только я это сделал, XPath «/ src: SRCExample / default: DataBlock / a: DocID / a: IDID» вернул мои результаты так, как я хотел. Надеюсь, это поможет прояснить проблему для других.
В этом случае это, вероятно, разрешение пространства имен, которое является причиной проблемы, но также возможно, что ваше выражение XPath само по себе не является правильным. Вы можете сначала оценить его.
Вот код с помощью XPathNavigator.
//xNav is the created XPathNavigator.
XmlNamespaceManager mgr = New XmlNamespaceManager(xNav.NameTable);
mgr.AddNamespace("prefix", "http://tempuri.org/");
XPathNodeIterator result = xNav.Select("/prefix:outerelement/prefix:innerelement", mgr);
Я использовал взломанный, но полезный подход, описанный SpikeDog выше. Он работал очень хорошо, пока я не бросил в него выражение xpath, которое использовало каналы для объединения нескольких путей.
Итак, я переписал его с использованием регулярных выражений и думал, что делюсь:
public string HackXPath(string xpath_, string prefix_)
{
return System.Text.RegularExpressions.Regex.Replace(xpath_, @"(^(?![A-Za-z0-9\-\.]+::)|[A-Za-z0-9\-\.]+::|[@|/|\[])(?'Expression'[A-Za-z][A-Za-z0-9\-\.]*)", x =>
{
int expressionIndex = x.Groups["Expression"].Index - x.Index;
string before = x.Value.Substring(0, expressionIndex);
string after = x.Value.Substring(expressionIndex, x.Value.Length - expressionIndex);
return String.Format("{0}{1}:{2}", before, prefix_, after);
});
}
Мой ответ расширяет предыдущий ответ Брэндона. Я использовал свой пример для создания метода расширения следующим образом:
static public class XmlDocumentExt
{
static public XmlNamespaceManager GetPopulatedNamespaceMgr(this System.Xml.XmlDocument xd)
{
XmlNamespaceManager nmsp = new XmlNamespaceManager(xd.NameTable);
XPathNavigator nav = xd.DocumentElement.CreateNavigator();
foreach (KeyValuePair<string,string> kvp in nav.GetNamespacesInScope(XmlNamespaceScope.All))
{
string sKey = kvp.Key;
if (sKey == "")
{
sKey = "default";
}
nmsp.AddNamespace(sKey, kvp.Value);
}
return nmsp;
}
}
Затем в моем XML-синтаксическом коде я просто добавляю одну строку:
XmlDocument xdCandidate = new XmlDocument();
xdCandidate.Load(sCandidateFile);
XmlNamespaceManager nmsp = xdCandidate.GetPopulatedNamespaceMgr(); // 1-line addition
XmlElement xeScoreData = (XmlElement)xdCandidate.SelectSingleNode("default:ScoreData", nmsp);
Мне очень нравится это потому что он полностью динамичен с точки зрения загрузки пространств имен из исходного XML-файла и не полностью игнорирует концепцию пространств имен XML, поэтому это можно использовать с XML, для которого требуется несколько пространств имен для deconfliction.
Для тех, кто ищет быстрое решение для взлома, особенно в тех случаях, когда вы знаете XML, и вам не нужно беспокоиться об пространствах имен и обо всем этом, вы можете обойти эту досадную небольшую «функцию», просто прочитав файл строку и замену атрибута оскорбительности:
XmlDocument doc = new XmlDocument();
string fileData = File.ReadAllText(fileName);
fileData = fileData.Replace(" xmlns=\"", " whocares=\"");
using (StringReader sr = new StringReader(fileData))
{
doc.Load(sr);
}
XmlNodeList nodeList = doc.SelectNodes("project/property");
Я нахожу это проще, чем все другие не-чувства, требующие префикса для пространства имен по умолчанию, когда я имею дело с одним файлом. Надеюсь, это поможет.
В случае, если пространства имен отличаются для outerelement и innerelement
XmlNamespaceManager manager = new XmlNamespaceManager(myXmlDocument.NameTable);
manager.AddNamespace("o", "namespaceforOuterElement");
manager.AddNamespace("i", "namespaceforInnerElement");
string xpath = @"/o:outerelement/i:innerelement"
// For single node value selection
XPathExpression xPathExpression = navigator.Compile(xpath );
string reportID = myXmlDocument.SelectSingleNode(xPathExpression.Expression, manager).InnerText;
// For multiple node selection
XmlNodeList myNodeList= myXmlDocument.SelectNodes(xpath, manager);
В моем случае добавление префикса было непрактичным. Слишком большая часть xml или xpath была определена во время выполнения. В конце концов я расширил методы на XmlNode. Это не было оптимизировано для производительности, и, вероятно, оно не обрабатывает все случаи, но оно работает для меня до сих пор.
public static class XmlExtenders
{
public static XmlNode SelectFirstNode(this XmlNode node, string xPath)
{
const string prefix = "pfx";
XmlNamespaceManager nsmgr = GetNsmgr(node, prefix);
string prefixedPath = GetPrefixedPath(xPath, prefix);
return node.SelectSingleNode(prefixedPath, nsmgr);
}
public static XmlNodeList SelectAllNodes(this XmlNode node, string xPath)
{
const string prefix = "pfx";
XmlNamespaceManager nsmgr = GetNsmgr(node, prefix);
string prefixedPath = GetPrefixedPath(xPath, prefix);
return node.SelectNodes(prefixedPath, nsmgr);
}
public static XmlNamespaceManager GetNsmgr(XmlNode node, string prefix)
{
string namespaceUri;
XmlNameTable nameTable;
if (node is XmlDocument)
{
nameTable = ((XmlDocument) node).NameTable;
namespaceUri = ((XmlDocument) node).DocumentElement.NamespaceURI;
}
else
{
nameTable = node.OwnerDocument.NameTable;
namespaceUri = node.NamespaceURI;
}
XmlNamespaceManager nsmgr = new XmlNamespaceManager(nameTable);
nsmgr.AddNamespace(prefix, namespaceUri);
return nsmgr;
}
public static string GetPrefixedPath(string xPath, string prefix)
{
char[] validLeadCharacters = "@/".ToCharArray();
char[] quoteChars = "\'\"".ToCharArray();
List<string> pathParts = xPath.Split("/".ToCharArray()).ToList();
string result = string.Join("/",
pathParts.Select(
x =>
(string.IsNullOrEmpty(x) ||
x.IndexOfAny(validLeadCharacters) == 0 ||
(x.IndexOf(':') > 0 &&
(x.IndexOfAny(quoteChars) < 0 || x.IndexOfAny(quoteChars) > x.IndexOf(':'))))
? x
: prefix + ":" + x).ToArray());
return result;
}
}
Затем в вашем коде просто используйте что-то вроде
XmlDocument document = new XmlDocument();
document.Load(pathToFile);
XmlNode node = document.SelectFirstNode("/rootTag/subTag");
Надеюсь, это поможет
При использовании XPath в .NET (через навигатор или SelectNodes / SelectSingleNode) в XML с пространствами имен вам необходимо:
Последнее (перефразировано из источника MS, связанного ниже): поскольку XPath 1.0 игнорирует спецификации пространства имен по умолчанию (xmlns = "some_namespace"). Поэтому, когда вы используете имя элемента без префикса, он принимает пустое пространство имен.
Вот почему реализация .NET XPath игнорирует пространство имен с префиксом String.Empty в XmlNamespaceManager и всегда использует пустое пространство имен.
См. XmlNamespaceManager и UndefinedXsltContext не обрабатывают пространство имен по умолчанию для получения дополнительной информации.
Я нахожу эту «функцию» очень неудобной, потому что вы не можете создавать старые пространства имен XPath, просто добавляя декларацию пространства имен по умолчанию , но вот как это работает.
/root/child
, потому что неперечисленный тест QName выбирает элементы под пустым или пустым пространством имен по определению .
– user
30 December 2010 в 21:17
<el xmlns="URI"/>
имеет QName ('URI', 'el', ''), эквивалентный этому другому элементу <pre:el xmlns:pre="URI"/>
('URI', 'el', 'pre'), но отличается от этого последнего элемента <el xmlns:pre="URI"/>
('', 'el', '')
– user
3 January 2011 в 17:13
Или, если кто-то должен использовать XPathDocument, например me:
XPathDocument xdoc = new XPathDocument(file);
XPathNavigator nav = xdoc.CreateNavigator();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(nav.NameTable);
nsmgr.AddNamespace("y", "http://schemas.microsoft.com/developer/msbuild/2003");
XPathNodeIterator nodeIter = nav.Select("//y:PropertyGroup", nsmgr);
nsmgr.AddNamespace("", el.OwnerDocument.DocumentElement.NamespaceURI);
) делает это пространство имен по умолчанию. Однако, к сожалению, это не означает, что вы можете использовать XPath без использования префикса (например,var nodes = el.SelectNodes(@"/outerelement/innerelement", nsmgr);
). Только это вы можете увидеть с помощьюnsmgr.DefaultNamespace
. Подробнее здесь: stackoverflow.com/a/4271875/361842 . Комментарий добавлен, чтобы сэкономить время, если вы хотите избежать использования префиксов; т. е. вы не можете. – JohnLBevan 6 April 2017 в 17:54xmlns=
наxmlns:p
, где p может быть любым допустимым префиксом, ваш код должен работать как есть. – Ravi M Patel 13 December 2017 в 14:04XElement does not contain a definition for OwnerDocument...
, не могли бы вы посмотреть на него? imgur.com/a/TPHVeoM – Luke 28 June 2018 в 17:39