Пространства имен XML и XPath - PullRequest
8 голосов
/ 18 апреля 2011

У меня есть приложение, которое должно загружать XML-документ и выходные узлы в зависимости от XPath.

Предположим, я начинаю с такого документа:

<aaa>
  ...[many nodes here]...
  <bbb>text</bbb>
  ...[many nodes here]...
  <bbb>text</bbb>
  ...[many nodes here]...
</aaa>

С XPath //bbb

Пока все хорошо.

И выбор doc.SelectNodes("//bbb"); возвращает список необходимых узлов.

Затем кто-то загружает документ с одним узлом, таким как <myfancynamespace:foo/>, и дополнительным пространством имен в корневом теге, и все ломается.

Почему? //bbb не наплевать на myfancynamespace, теоретически это должно быть даже хорошо с //myfancynamespace:foo, так как нет никакой двусмысленности, но выражение возвращает 0 результатов, и все.

Есть ли способ обойти это поведение?

У меня есть менеджер пространства имен для документа, и я передаю его в запрос Xpath. Но пространства имен и префиксы мне неизвестны, поэтому я не могу добавить их до запроса.

Должен ли я предварительно проанализировать документ, чтобы заполнить диспетчер пространства имен, прежде чем делать какие-либо выборы? Почему такое поведение, это просто не имеет смысла.

EDIT:

Я использую: XmlDocument и XmlNamespaceManager

EDIT2:

XmlDocument doc = new XmlDocument();
doc.XmlResolver = null;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
//I wish I could:
//nsmgr.AddNamespace("magic", "http://magicnamespaceuri/
//...
doc.LoadXML(usersuppliedxml);
XmlNodeList nodes = doc.SelectNodes(usersuppliedxpath, nsmgr);//usersuppliedxpath -> "//bbb"

//nodes.Count should be > 0, but with namespaced document they are 0

EDIT3: Нашел статью, которая описывает реальный сценарий проблемы с одним обходным путем, но не очень симпатичным обходным путем: http://codeclimber.net.nz/archive/2008/01/09/How-to-query-a-XPath-doc-that-has-a-default.aspx

Почти кажется, что удаление xmlns - это путь ...

Ответы [ 4 ]

13 голосов
/ 18 апреля 2011

Вам не хватает всего смысла в пространствах имен XML.

Но если вам действительно нужно выполнить XPath для документов, которые будут использовать неизвестное пространство имен, и вам на самом деле все равнораздеть его и перезагрузить документ.XPath не будет работать независимо от пространства имен, если только вы не хотите использовать функцию local-name() в каждой точке ваших селекторов.

private XmlDocument StripNamespace(XmlDocument doc)
{
    if (doc.DocumentElement.NamespaceURI.Length > 0)
    {
        doc.DocumentElement.SetAttribute("xmlns", "");
        // must serialize and reload for this to take effect
        XmlDocument newDoc = new XmlDocument();
        newDoc.LoadXml(doc.OuterXml);
        return newDoc;
    }
    else
    {
        return doc;
    }
}
6 голосов
/ 18 апреля 2011

<myfancynamespace:foo/> не обязательно совпадает с <foo/>.

Пространства имен имеют значение. Но я могу понять ваше разочарование , поскольку они обычно имеют тенденцию ломать коды, поскольку различные реализации (C #, Java, ...) имеют тенденцию выводить его по-разному.

Я предлагаю вам изменить свой XPath, чтобы разрешить прием всех пространств имен. Например вместо

//bbb 

Определите его как

//*[local-name()='bbb']

Это должно позаботиться об этом.

0 голосов
/ 18 апреля 2011

Вы можете использовать классы LINQ XML, такие как XDocument. Они значительно упрощают работу с пространствами имен.

0 голосов
/ 18 апреля 2011

Вы должны описать немного более подробно, что вы хотите сделать.То, как вы задаете вопрос, не имеет никакого смысла.Пространство имен - это только часть имени.Ни больше ни меньше.Таким образом, ваш вопрос такой же, как запрос запроса XPath, чтобы получить все теги, заканчивающиеся на «x».Это не идея XML, но если у вас есть странные причины для этого: не стесняйтесь перебирать все узлы и реализовывать их самостоятельно.То же самое относится и к запрашиваемым вами функциям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...