Имя: Пароль:
1C
1C 7.7
v7: как узнать префиксы пространства имен по namespaceURI (MSXML.DOMDocument)
,
0 gugolovski
 
04.06.21
08:03
есть некий xlm документ.
namespaceURI неизменный, а префиксы меняются из раза в раз
Например:
1)
<?xml version="1.0" encoding="UTF-8" ?>
<ns:Documents h:table xmlns:h="http://www.w3.org/TR/html4/">...

Здесь
prefix = h
namespaceURI = "http://www.w3.org/TR/html4/"

2)<?xml version="1.0" encoding="UTF-8" ?>
<ns:Documents h:table xmlns:a="http://www.w3.org/TR/html4/">...
prefix = а
namespaceURI = "http://www.w3.org/TR/html4/"


загружаем документ..
xlm=СоздатьОбъект("MSXML.DOMDocument");
xlm.load(файл);

Можно ли по namespaceURI узнать префикс текущего пространства имен?
1 Василий Алибабаевич
 
04.06.21
08:16
(0) Вот здесь : https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms760428(v=vs.85) есть пример на жабе. И пишут что оно есть просто свойство конкретного элемента.
2 Василий Алибабаевич
 
04.06.21
08:17
+ (1) В примере получают все ПространстваИмен объявленные в схеме по адресу ПространстваИменУРИ.
3 MWWRuza
 
гуру
04.06.21
14:58
Это по ходу, задача автора топика - ТТНки ЕГАИС... Некоторые поставщики-извращенцы, любят такое делать. Схемы позволяют... Каких только префиксов иногда не придумывают :-)
Я когда с таким столкнулся, стал придумывать, как с этим бороться. Соорудил, некое решение, не уверен, что оптимальное, но работает...
Из УТМ получаю таблицу "стандартных префиксов"(из схем), и парсинг новой ТТН, начинаю с чтения заголовка и сопоставления в таблице стандартных префиксов, префиксов полученных из заголовков стандартным префиксам. Сопоставление делаю по namespaceURI. Таблицу эту храню в переменной на время парсинга этой ХМЛки... Там, где мне нужно получить нужный текущий "префикс от извращенцев", получаю его функцией из этой таблицы ТекПрефикс([имя стандартного префикса])... Имя стандартного префикса, это то имя, которое в данном месте ожидалось, согласно описанию УТМа.

Еще раз! Не утверждаю, что такая схема оптимальна, и нельзя сделать что-то проще, но... Сделано давно, успешо работает...

Варианты парсить ХМЛ как текст, просто по именам тегов - не рассматриваю, MSXML через DOM как-то нравится больше...
А там, вроде, без префиксов не обойтись(хотя, могу и ошибаться).

Единственное, при переходе на УТМ4, пришлось поправить функцию получения таблицы "стандартных префиксов", т.к., схемы документов там по другому хранятся...
И вообще, такое ощущение, что УТМ4 писался совсем другой командой разработчиков "с нуля", там много чего по другому, чем в УТМ 1, 2 и 3, чего можно было и не трогать... Нооо... Что есть, то есть.
4 gugolovski
 
07.06.21
09:04
(3) Да все верно ТТН-ки.) Завис с этими префииксами. Не могу получить их. Не знаю какой командой их извлекать
Например,
xlm=СоздатьОбъект("MSXML.DOMDocument");
xlm.load(файл);
коллекцияNS = xlm.namespaces;
Для сч = 0 По коллекцияNS.length-1 Цикл
Сообщить(коллекцияNS.namespaceURI(сч));  
КонецЦикла;

Здесь получаю URI:
http://www.w3.org/TR/html4/, а как получить префикс?
5 zenik
 
07.06.21
09:21
А зачем префиксы то?

xmldoc = СоздатьОбъект("Msxml2.DOMDocument.6.0");
xmldoc.async = 0;
xmldoc.load(Файл);
Для n = 0 По xmldoc.childnodes.length - 1 Цикл
  ChildNodes = xmldoc.childnodes.item(n);
  Сообщить(ChildNodes.BaseName);
КонецЦикла;

ChildNodes.BaseName - будет без всяких префиксов...
6 MWWRuza
 
гуру
07.06.21
09:21
Еще раз предупреждаю - не претендую на оптимальность кода, критиковать бесполезно, делал давно, и с появлением УТМ4 дописывал по методу "латания дыр". Но, работает.
И, это не весь код, могут быть ссылки на какие-то функции, которых нет в этом фрагменте, но, общий принцип - думаю поможет понять. Если что-то не понятно - пишите, дополню...

Функция ПолучитьТзСтандартныхПрефиксов()
    ТЗ = СоздатьОбъект("ТаблицаЗначений");
    ТЗ.НоваяКолонка("СтПреф");
    ТЗ.НоваяКолонка("URL");
    ОП         = глЗначениеПоУмолчанию("ОсновнаяФирма").ЮрЛицо;
    УТМ_URL = СокрЛП(ОП.УТМ_URL);
    СЗ         = ПолучитьВерсиюИ_ЕГАИС_ID(УТМ_URL);
    Версия  = Лев(СЗ.Получить("Версия"), 1);
    Если Версия = "4" Тогда
        URL     = УТМ_URL + "api/schema/WB_DOC_SINGLE_01.xsd"; // URL Схемы документов XSD из УТМ 4
    Иначе    
        URL     = УТМ_URL + "info/xsdWholesale/WEGAIS/WB_DOC_SINGLE_01.xsd"; // URL Схемы документов XSD
    КонецЕсли;
    Скрипт    = СоздатьОбъект("MSScriptControl.ScriptControl");
    Скрипт.language="vbscript";
    Это     = Скрипт.Eval("this");
    WinHttp = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
    Скрипт.AddObject("WinHttp",WinHttp);
    WinHttp.Open("GET", URL, 0);
    Попытка
        WinHttp.Send();
    Исключение
        Сообщить("Служба УТМ не запущена, невозможно получить список входящих документов!");
        Возврат "";
    КонецПопытки;    
    Если WinHTTP.Status<>200 Тогда
        Предупреждение("Не удалось загрузить документ. Возможно он удалён или служба УТМ не запущена.");
        Возврат "";
    КонецЕсли;
    Стрим = СоздатьОбъект("ADODB.Stream");
    Стрим.Mode = 3;
    Стрим.Type = 1;
    Стрим.Open();
    Скрипт.AddObject("Stream",Стрим);
    XML_DOM    = CreateObject("MSXML2.DOMDocument.6.0");
    Скрипт.Eval("Stream.Write(WinHttp.responseBody)");
    Стрим.Position = 0;
    Стрим.Type         = 2;
    Стрим.Charset     = "utf-8";
    Ответ             = Стрим.ReadText();
    Стрим.Close();
    Если Версия = "4" Тогда
        СтрСхем            = Ответ;
    Иначе
        НачТела            = Найти(Ответ,"<pre>");
        Ответ            = Сред(Ответ,НачТела);
        КонТела            = Найти(Ответ,"</pre>") + 5;
        Ответ            = Лев(Ответ,КонТела);
        XML_DOM.LoadXML(Ответ);
        NamRootNodSchem = XML_DOM.DocumentElement.selectSingleNode("/*").NodeName;
        СтрСхем         = XML_DOM.selectSingleNode(NamRootNodSchem).text;        
    КонецЕсли;
    Пока Найти(СтрСхем,"xmlns:") > 0 Цикл
        ОстСтр         = Сред(СтрСхем,Найти(СтрСхем,"xmlns:") + 6);
        НачАдреса    = Найти(ОстСтр,"=");
        ТекПреф        = Лев(ОстСтр,НачАдреса - 1);
        ТекПреф        = СтрЗаменить(ТекПреф,"2","");
        ТекПреф        = СтрЗаменить(ТекПреф,"3","");
        ОстСтр        = Сред(ОстСтр,НачАдреса + 2);
        КонАдреса    = Найти(ОстСтр,"""") - 1;
        ТекАдрес    = Сред(ОстСтр,1,КонАдреса);
        СтрСхем     = ОстСтр;
        ТЗ.НоваяСтрока();
        ТЗ.СтПреф    = ТекПреф;
        ТЗ.URL        = ТекАдрес;        
    КонецЦикла;
    ТЗ.Сортировать("СтПреф, URL");
    Возврат ТЗ;    
КонецФункции

Функция ТекПреф(СтПр) Экспорт
    ТекСтрСоот    = "";
    ТекПреф        = "";
    Если ТабПреф.НайтиЗначение(СтПр,ТекСтрСоот,"СтПреф") = 1 Тогда
        ТекПреф = ТабПреф.ПолучитьЗначение(ТекСтрСоот,"НовПреф");  
    КонецЕсли;
    Возврат ТекПреф;    
КонецФункции

Процедура ЗаполнитьТабПростИмен(nod)  // Рекурсивная процедура, пробегает по всему DOM и вытаскивает из него прециксы и URL_NS в ТЗ.
    ИмяПреф = nod.prefix;
    URL_NS    = nod.namespaceURI;    
    Если СокрЛП(ИмяПреф) <> "" Тогда
        ТабПреф.НоваяСтрока();
        ТабПреф.НовПреф    = ИмяПреф;
        ТабПреф.URL        = URL_NS;
        ТабПреф.Сверт    = 1;        
    КонецЕсли;
    node = nod.childNodes;
    Ind    = 0;
    Для Ind = 1 По node.Length Цикл
        ChildNod    = node.item(ind - 1);
        ИмяПреф = ChildNod.prefix;
        URL_NS    = ChildNod.namespaceURI;
        Если СокрЛП(ИмяПреф) <> "" Тогда
            ТабПреф.НоваяСтрока();
            ТабПреф.НовПреф    = ИмяПреф;
            ТабПреф.URL        = URL_NS;
            ТабПреф.Сверт    = 1;
        КонецЕсли;        
        ЗаполнитьТабПростИмен(ChildNod);
    КонецЦикла;
КонецПроцедуры
7 MWWRuza
 
гуру
07.06.21
09:24
Во... В (6), как раз то, о чем я думал - надо вообще от префиксов избавиться при парсинге. Это намного оптимальнее. Надо будет попробовать... Только теперь, переделывать уже много, лень :-(
8 gugolovski
 
07.06.21
10:40
(6) как я понимаю в этом куске кода делается выборка из схем документов XSD: в таблицу значений прописываются пространства имен и префиксы данные разработчиками. а как выдергивать префиксы их ТТН полученные от поставщика?
9 MWWRuza
 
гуру
07.06.21
12:55
Вот: Процедура ЗаполнитьТабПростИмен(nod)  // Рекурсивная процедура, пробегает по всему DOM и вытаскивает из него прециксы и URL_NS в ТЗ.

Это собираются все префиксы из текущей ХМЛки, которую парсите.

Сами строки ХМЛ читаете например так:
DocumentNode         = XML_DOM.selectSingleNode("/" + ТекПреф("ns") + ":Documents/" + ТекПреф("ns") + ":Document").firstChild;

В функции ТекПреф("ns") - "ns", это тот префикс который стандартный, заданный в схемах содержащихся в УТМ. Соответственно, "ns" будет заменен на тот префикс, который ему соответствует и находится на этом месте в реальной ХМЛ.

PS Но, лучше, не идти по этому пути, а попытаться разобраться по методике как в (6) предложено...
10 victuan1
 
08.06.21
05:58
(9) в (6) или (5) всё-таки?
11 MWWRuza
 
гуру
08.06.21
09:53
(10) Не понял вопрос... (9) был ответ на предыдущее, (8).
12 trad
 
08.06.21
10:17
(0) не надо узнавать "чужие" префиксы, надо работать со своими префиксами для пространств имен.
Используй
xlm.setProperty("SelectionNamespaces", "xmlns:h='http://www.w3.org/TR/html4/'");
Вот тут "xmlns:h=" вместо h можешь сохранить любой из "чужих" или придумать свой префикс.
И далее, в коде, обращаться к узлам всегда h:table (с применением, указанного в SelectionNamespaces, префикса)

ps
можно перечислить все употребимые в коде префиксы
в xlm.setProperty("SelectionNamespaces", "xmlns:h='http://www.w3.org/TR/html4/'
|xmlns:pr1='NS1'
|xmlns:pr2='NS2'
|...
|");
13 gugolovski
 
08.06.21
13:45
(9) Мне понравился ваш метод с рекурсией - теперь знаю как обежать весь документ xml.
Но остановлюсь на варианте: (12) setProperty - очень просто, красиво, легко.
Ребята, спасибо огромное)