Как указать пространство имен при запросе узлов с XPath? - PullRequest
0 голосов
/ 28 февраля 2019

Короткая версия

  • Вы делаете это в .NET с помощью:

    XmlNode.SelectNodes(query, selectionNamespaces);
    
  • Можете ли вы сделать это в JavaScript?

  • Можете ли вы сделать это в формате msxml?

Попытка A :

IXMLDOMNode.selectNodes(query); //no namespaces option

Попытка B :

IXMLDOMNode.ownerDocument.setProperty("SelectionNamespaces", selectionNamespaces);
IXMLDOMNode.selectNodes(query); //doesn't work

Попытка C :

IXMLDOMDocument3 doc;
doc.setProperty("SelectionNamespaces", selectionNamespaces);
IXMLDOMNodeList list = doc.selectNodes(...)[0].selectNodes(query); //doesn't work

Длинная версия

Учитывая IXMLDOMNode , содержащий фрагмент xml:

<row>
    <cell>a</cell>
    <cell>b</cell>
    <cell>c</cell>
</row>

Мы можем использовать IXMLDOMNode.selectNodes метод выбора дочерних элементов:

IXMLDOMNode row = //...xml above

IXMLDOMNodeList cells = row.selectNodes("/row/cell");

, который возвращает IXMLDOMNodeList :

  • <cell>a</cell>
  • <cell>b</cell>
  • <cell>c</cell>

И это нормально.

Но пространства имен нарушают его

Если фрагмент XML возник из документа спространство имен, например:

<row xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <cell>a</cell>
    <cell>b</cell>
    <cell>c</cell>
</row>

Тот же запрос XPath ничего не даст, потому что элементы row и cell не существуют;они находятся в другом пространстве имен.

Запрос документов с пространством имен по умолчанию

Если бы у вас был полный IXMLDOMDocument , вы бы использовали метод setProperty , чтобы установить пространство имен выбора:

abc

Вы бы запросили пространство имен по умолчанию с помощью , дав имя, например:

и тогда вы сможете запросить его:

IXMLDOMDocument3 doc = //...document xml above
doc.setProperty("SelectionNamespaces", "xmlns:peanut="http://schemas.openxmlformats.org/spreadsheetml/2006/main");

IXMLDOMNodeList cells = doc.selectNodes("/peanut:row/peanut:cell");

и вы получите свои клетки:

  • <cell>a</cell>
  • <cell>b</cell>
  • <cell>c</cell>

Но это не работает для узла

IXMLDOMNode имеет метод для выполнения запросов XPath:

Метод selectNodes

Применяет указанную операцию сопоставления с шаблоном к контексту этого узла и возвращает список совпадающих узлов как IXMLDOMNodeList.

HRESULT selectNodes(  
      BSTR expression,  
      IXMLDOMNodeList **resultList); 

Примечания

Длябольше информации об использовании метода selectNodes с пространствами имен, см. the setProperty Method topic.

Но невозможно указать пространства имен Selection при выполнении запроса XPath для узла DOM.

Как указать пространство именпри запросе узлов с XPath?

.NET Solution

.NET XmlNode предоставляет метод SelectNodes , который обеспечивает прием параметра XmlNamespaceManager:

XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("peanut", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
cells = row.SelectNodes("/peanut:row/peanut:cell", ns);

Но я не на C # (и я не в Javascript).Что такое нативный эквивалент msxml6?

Редактировать : Я не так много с Javascript ( jsFiddle )

Complete MinimalПример

program Project3;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, msxml, ActiveX;

procedure Main;
var
    s: string;
    doc: DOMDocument60;
    rows: IXMLDOMNodeList;
    row: IXMLDOMElement;
    cells: IXMLDOMNodeList;
begin
    s :=
            '<?xml version="1.0" encoding="UTF-16" standalone="yes"?>'+#13#10+
            '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'+#13#10+
            '<row>'+#13#10+
            '    <cell>a</cell>'+#13#10+
            '    <cell>b</cell>'+#13#10+
            '    <cell>c</cell>'+#13#10+
            '</row>'+#13#10+
            '</worksheet>';

    doc := CoDOMDocument60.Create;
    doc.loadXML(s);
    if doc.parseError.errorCode <> 0 then
        raise Exception.CreateFmt('Parse error: %s', [doc.parseError.reason]);

    doc.setProperty('SelectionNamespaces', 'xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main"');

    //Query for all the rows
    rows := doc.selectNodes('/ss:worksheet/ss:row');
    if rows.length = 0 then
        raise Exception.Create('Could not find any rows');

    //Do stuff with the first row
    row := rows[0] as IXMLDOMElement;

    //Get the cells in the row
    (row.ownerDocument as IXMLDOMDocument3).setProperty('SelectionNamespaces', 'xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main"');
    cells := row.selectNodes('/ss:row/ss:cell');
    if cells.length <> 3 then
        raise Exception.CreateFmt('Did not find 3 cells in the first row (%d)', [cells.length]);
end;

begin
  try
        CoInitialize(nil);
        Main;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

1 Ответ

0 голосов
/ 01 марта 2019

Ответ на MSDN:

Как указать пространство имен при запросе DOM с XPath

Обновление:

Обратите внимание, что во втором примере XML элементы <row> и <cell> НЕ находятся в пространстве имен, запрашиваемом XPath при добавлении xmlns:peanut к свойству SelectionNamespaces.Вот почему элементы <cell> не найдены.

Чтобы правильно разместить их в пространстве имен, вам потребуется:

Свойство SelectionNamespaces волшебным образом не помещает элементы в пространство имен для вас, оно только указывает, какие пространства имен доступны для использования запроса XPath.Сам XML должен по мере необходимости помещать элементы в соответствующие пространства имен.

Обновление:

В вашем новом примере cells := row.selectNodes('/ss:row/ss:cell'); не работает, поскольку запрос XPathиспользуя абсолютный путь, где начальный / начинается в корне документа, а в верхней части XML-документа нет элементов <row>, только элемент <worksheet>.Вот почему rows := doc.selectNodes('/ss:worksheet/ss:row'); работает.

Если вы хотите выполнить запрос XPath, начинающийся с запрашиваемого узла, не используйте путь absolute , используйте относительный путь вместо:

cells := row.selectNodes('ss:row/ss:cell');

Или просто:

cells := row.selectNodes('ss:cell');
...