Пространство имен XML, ломающее мой xpath!
У меня есть следующий XML:
<List xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Fields>
<Field>
</Field>
</Fields>
</List>
Это уменьшенная версия XML, возвращаемого из веб-службы SharePoint. У меня также есть следующий xPath:
/List/Fields/Field
Когда я удаляю xmlns
из моего XML xPath работает нормально. Когда он там, мой xPath ничего не находит. Есть ли что-то, что я должен делать по-другому с моим xPath? Изменение XML не вариант.
5 ответов
У меня также есть следующий xPath:
/List/Fields/Field
Когда я удаляю xmlns из моего XML, xPath работает нормально. Когда он там, мой xPath ничего не находит
Если вы не можете зарегистрировать привязку пространства имен и не можете использовать (при условии, что зарегистрированный префикс - "x"):
/x:List/x:Fields/x:Field
тогда есть другой способ:
/*[name()='List']/*[name()='Fields']/*[name()='Field']
Элемент List был определен с пространством имен по умолчанию, и это принимается всеми элементами внутри.
Поэтому вам нужно игнорировать пространство имен элемента следующим образом:
/*[local-name()='List']/*[local-name()='Fields]/*[local-name()='Field]
но это означает, что xpath выберет любой другой элемент с List - Fields - Field
Вы можете выполнить проверку пространства имен, а также проверку локального имени следующим образом:
/*[local-name()='List' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']/*[local-name()='Fields' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']/*[local-name()='Field' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']
Или вы можете зарегистрировать пространство имен в библиотеке, а затем явно указать префикс для этого пространства имен и добавить его в выражение xpath, метод которого зависит от используемой вами библиотеки.
Скорее всего, вам придется зарегистрировать это пространство имен uri в вашей библиотеке xpath. В зависимости от библиотеки вы можете использовать префикс "по умолчанию" или вам может потребоваться присвоить ей именованный префикс и использовать его в запросах xpath.
Например, в php (поскольку вы не указали язык), используя DOMXPath, вы можете сделать что-то вроде этого:
$xpath = new DOMXPath($document);
$xpath->registerNamespace('x', 'http://schemas.microsoft.com/sharepoint/soap/');
$xpath->query('/x:List/x:Fields/x:Field');
Я только что имел эту проблему при использовании Xalan-C
Сначала я не совсем понял, что псевдонимы / префиксы пространств имен XPath или XSLT могут отличаться от таковых в документе - в зависимости от вашего преобразователя пространства имен.
Похоже, что если в документе есть пространство имен, то оно не может соответствовать элементу пути, если только не используется пространство имен. (стандартно, но не всегда соблюдается?)
XalanDocumentPrefixResolver отобразит пространства имен XPath или XSLT в URI и попытается дать им идентификатор, получив префикс - там, где нет префикса, он использовал имя, которое превратилось в xmlns
/xmlns:List/xmlns:Fields/xmlns:Field
В качестве альтернативы вы можете создать свой собственный распознаватель, но он все еще требует минимального пространства имен, используемого в xpath:(
Вот тот, который я взломал вместе во время тестирования, нет гарантии памяти
// don't care what prefix given, there can only be the one
struct NoPrefixResolver : public xalanc::PrefixResolver {
NoPrefixResolver(const xalanc::XalanDOMString& theURI) : m_uri(theURI){}
virtual const xalanc::XalanDOMString*
getNamespaceForPrefix(const xalanc::XalanDOMString& prefix) const {
return &m_uri;
}
virtual const xalanc::XalanDOMString& getURI() const {
return m_uri;
}
const xalanc::XalanDOMString m_uri;
};
/x:List/x:Fields/x:Field
/a:List/b:Fields/c:Field
Если вы можете пропустить элемент документа, следующий XPath также может помочь:
//Fields/Field
Это работает до тех пор, пока у вас нет "Поля" под любым другим узлом, и пока у подузлов нет пространства имен.