Для тех, кто имеет дело с обменами данных и взаимодействием с интернет-приложениями, часто возникает необходимость открыть на просмотр в 1С XML с незнакомой структурой. Что делать?
Разнообразные предшественники
- //infostart.ru/public/16386/
- //infostart.ru/public/14610/
- //infostart.ru/public/21664/
- //infostart.ru/public/21664/
пробовали заниматься автоматическим анализом структуры XML, создавали более или менее универсальные утилиты программного разбора, используя при этом разнообразные «нагруженные» объекты 1С типа ТаблицаЗначений, ДеревоЗначений, либо в худшем (для универсальности и переносимости) случае подключали внешние компоненты.
Но неужели нет простых средств, с минимальными затратами и желательно без программирования?
Конечно, можно поместить текст XML в Поле текстового документа. Но если XML получен из источника, который формировал его автоматически, то скорее всего текст будет неотформатирован и плохо читаем, например:
Заметим, что форматирование XML задача несложная. Ее стандартно решает объект ЗаписьXML (свойство Отступ либо объект ПараметрыЗаписиXML), примерно так:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ИсходныйТекстXML);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку(Новый ПараметрыЗаписиXML(, , Истина, Истина));//здась как раз и содержится явное указание 1С отформатировать XML при записи
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
ИсходныйТекстXML= ЗаписьXML.Закрыть();
В результате получаем читаемый документ:
Но так отобразить может только в поле текстового документа (причем без подсветки синтаксиса и без свертывания уровней).
Но при работе с интернет задача же часто стоит отображать XML именно в поле HTML-документа. Как?
Если в ПолеHTMLДокумента поместить некий произвольный XML, то 1С ничего не отобразит.
Не поможет и попытка предварительного чтения XML объектами 1С, к примеру:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(OriginXML);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
ЗаписьHTML = Новый ЗаписьHTML;
ЗаписьHTML.УстановитьСтроку();
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьHTML);
XML2HTML = ЗаписьHTML.Закрыть();
Однако известно, что в отличие от ПолеHTMLДокумента из 1С, интернет-броузеры умеют отображать текст произвольых XML-документов. Примерно так:
Оказывается, делают они это с помощью встроенных XSL-таблиц. Для IE в Windows такая таблица расположена на локальном компьютере по адресу: res://msxml3.dll/defaultss.xsl ( см. например http://www.script-coding.com/XSL.html или http://farinadesign.narod.ru/XMLtech/Lectures/DSO.html )
Поэтому задачу полностью решает использование XSL-преобразования (идея взята из //infostart.ru/public/184288/ ):
Преобразование = Новый ПреобразованиеXSL;
Преобразование.ЗагрузитьИзСтроки(ТекстПреобразованияXSL);
XML2HTML = Преобразование.ПреобразоватьИзСтроки(ИсходныйТекстXML);
Дополнительного программирования в 1С не требуется! Требуется только получитьподходящий default.xsl файл. Причем, естественно, варианты таких файлов могут отличаться. Предлагаю использовать следующий, полученный из предыдущих версий IE, исходник xsl-преобразования:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="no" method="html"/>
<xsl:template match="/">
<HTML>
<HEAD>
<SCRIPT>
<xsl:comment><![CDATA[
function f(e){
if (e.className=="ci") {
if (e.children(0).innerText.indexOf("
")>0) fix(e,"cb");
}
if (e.className=="di") {
if (e.children(0).innerText.indexOf("
")>0) fix(e,"db");
} e.id="";
}
function fix(e,cl){
e.className=cl;
e.style.display="block";
j=e.parentElement.children(0);
j.className="c";
k=j.children(0);
k.style.visibility="visible";
k.href="#";
}
function ch(e) {
mark=e.children(0).children(0);
if (mark.innerText=="+") {
mark.innerText="-";
for (var i=1;i<e.children.length;i++) {
e.children(i).style.display="block";
}
}
else if (mark.innerText=="-") {
mark.innerText="+";
for (var i=1;i<e.children.length;i++) {
e.children(i).style.display="none";
}
}
}
function ch2(e) {
mark=e.children(0).children(0);
contents=e.children(1);
if (mark.innerText=="+") {
mark.innerText="-";
if (contents.className=="db"||contents.className=="cb") {
contents.style.display="block";
}
else {
contents.style.display="inline";
}
}
else if (mark.innerText=="-") {
mark.innerText="+";
contents.style.display="none";
}
}
function cl() {
e=window.event.srcElement;
if (e.className!="c") {
e=e.parentElement;
if (e.className!="c") {
return;
}
}
e=e.parentElement;
if (e.className=="e") {
ch(e);
}
if (e.className=="k") {
ch2(e);
}
}
function ex(){}
function h(){window.status=" ";}
document.onclick=cl;
]]></xsl:comment>
</SCRIPT>
<STYLE>
BODY {font:x-small 'Verdana'; margin-right:1.5em}
.c {cursor:hand}
.b {color:red; font-family:'Courier New'; font-weight:bold;
text-decoration:none}
.e {margin-left:1em; text-indent:-1em; margin-right:1em}
.k {margin-left:1em; text-indent:-1em; margin-right:1em}
.t {color:#990000}
.xt {color:#990099}
.ns {color:red}
.dt {color:green}
.m {color:blue}
.tx {font-weight:bold}
.db {text-indent:0px; margin-left:1em; margin-top:0px;
margin-bottom:0px;padding-left:.3em;
border-left:1px solid #CCCCCC; font:small Courier}
.di {font:small Courier}
.d {color:blue}
.pi {color:blue}
.cb {text-indent:0px; margin-left:1em; margin-top:0px;
margin-bottom:0px;padding-left:.3em; font:small Courier;
color:#888888}
.ci {font:small Courier; color:#888888}
PRE {margin:0px; display:inline}
</STYLE>
</HEAD>
<BODY class="st">
<xsl:apply-templates/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="processing-instruction()">
<DIV class="e">
<SPAN class="b">
<xsl:call-template name="entity-ref">
<xsl:with-param name="name">nbsp</xsl:with-param>
</xsl:call-template>
</SPAN>
<SPAN class="m">
<xsl:text><?</xsl:text>
</SPAN>
<SPAN class="pi">
<xsl:value-of select="name(.)"/>
<xsl:value-of select="."/>
</SPAN>
<SPAN class="m">
<xsl:text>?></xsl:text>
</SPAN>
</DIV>
</xsl:template>
<xsl:template match="processing-instruction('xml')">
<DIV class="e">
<SPAN class="b">
<xsl:call-template name="entity-ref">
<xsl:with-param name="name">nbsp</xsl:with-param>
</xsl:call-template>
</SPAN>
<SPAN class="m">
<xsl:text><?</xsl:text>
</SPAN>
<SPAN class="pi">
<xsl:text>xml </xsl:text>
<xsl:for-each select="@*">
<xsl:value-of select="name(.)"/>
<xsl:text>="</xsl:text>
<xsl:value-of select="."/>
<xsl:text>" </xsl:text>
</xsl:for-each>
</SPAN>
<SPAN class="m">
<xsl:text>?></xsl:text>
</SPAN>
</DIV>
</xsl:template>
<xsl:template match="@*">
<SPAN>
<xsl:attribute name="class"><xsl:if test="xsl:*/@*"><xsl:text>x</xsl:text></xsl:if><xsl:text>t</xsl:text></xsl:attribute>
<xsl:value-of select="name(.)"/>
</SPAN>
<SPAN class="m">="</SPAN>
<B>
<xsl:value-of select="."/>
</B>
<SPAN class="m">"</SPAN>
</xsl:template>
<xsl:template match="text()">
<DIV class="e">
<SPAN class="b"> </SPAN>
<SPAN class="tx">
<xsl:value-of select="."/>
</SPAN>
</DIV>
</xsl:template>
<xsl:template match="comment()">
<DIV class="k">
<SPAN>
<A STYLE="visibility:hidden" class="b" false"
<SPAN class="m">
<xsl:text><!--</xsl:text>
</SPAN>
</SPAN>
<SPAN class="ci" id="clean">
<PRE>
<xsl:value-of select="."/>
</PRE>
</SPAN>
<SPAN class="b">
<xsl:call-template name="entity-ref">
<xsl:with-param name="name">nbsp</xsl:with-param>
</xsl:call-template>
</SPAN>
<SPAN class="m">
<xsl:text>--></xsl:text>
</SPAN>
<SCRIPT>f(clean);</SCRIPT>
</DIV>
</xsl:template>
<xsl:template match="*">
<DIV class="e">
<DIV STYLE="margin-left:1em;text-indent:-2em">
<SPAN class="b">
<xsl:call-template name="entity-ref">
<xsl:with-param name="name">nbsp</xsl:with-param>
</xsl:call-template>
</SPAN>
<SPAN class="m"><</SPAN>
<SPAN>
<xsl:attribute name="class"><xsl:if test="xsl:*"><xsl:text>x</xsl:text></xsl:if><xsl:text>t</xsl:text></xsl:attribute>
<xsl:value-of select="name(.)"/>
<xsl:if test="@*">
<xsl:text> </xsl:text>
</xsl:if>
</SPAN>
<xsl:apply-templates select="@*"/>
<SPAN class="m">
<xsl:text>/></xsl:text>
</SPAN>
</DIV>
</DIV>
</xsl:template>
<xsl:template match="*[node()]">
<DIV class="e">
<DIV class="c">
<A class="b" href="#" false"
<SPAN class="m"><</SPAN>
<SPAN>
<xsl:attribute name="class"><xsl:if test="xsl:*"><xsl:text>x</xsl:text></xsl:if><xsl:text>t</xsl:text></xsl:attribute>
<xsl:value-of select="name(.)"/>
<xsl:if test="@*">
<xsl:text> </xsl:text>
</xsl:if>
</SPAN>
<xsl:apply-templates select="@*"/>
<SPAN class="m">
<xsl:text>></xsl:text>
</SPAN>
</DIV>
<DIV>
<xsl:apply-templates/>
<DIV>
<SPAN class="b">
<xsl:call-template name="entity-ref">
<xsl:with-param name="name">nbsp</xsl:with-param>
</xsl:call-template>
</SPAN>
<SPAN class="m">
<xsl:text></</xsl:text>
</SPAN>
<SPAN>
<xsl:attribute name="class"><xsl:if test="xsl:*"><xsl:text>x</xsl:text></xsl:if><xsl:text>t</xsl:text></xsl:attribute>
<xsl:value-of select="name(.)"/>
</SPAN>
<SPAN class="m">
<xsl:text>></xsl:text>
</SPAN>
</DIV>
</DIV>
</DIV>
</xsl:template>
<xsl:template match="*[text() and not (comment() or processing-instruction())]">
<DIV class="e">
<DIV STYLE="margin-left:1em;text-indent:-2em">
<SPAN class="b">
<xsl:call-template name="entity-ref">
<xsl:with-param name="name">nbsp</xsl:with-param>
</xsl:call-template>
</SPAN>
<SPAN class="m">
<xsl:text><</xsl:text>
</SPAN>
<SPAN>
<xsl:attribute name="class"><xsl:if test="xsl:*"><xsl:text>x</xsl:text></xsl:if><xsl:text>t</xsl:text></xsl:attribute>
<xsl:value-of select="name(.)"/>
<xsl:if test="@*">
<xsl:text> </xsl:text>
</xsl:if>
</SPAN>
<xsl:apply-templates select="@*"/>
<SPAN class="m">
<xsl:text>></xsl:text>
</SPAN>
<SPAN class="tx">
<xsl:value-of select="."/>
</SPAN>
<SPAN class="m"></</SPAN>
<SPAN>
<xsl:attribute name="class"><xsl:if test="xsl:*"><xsl:text>x</xsl:text></xsl:if><xsl:text>t</xsl:text></xsl:attribute>
<xsl:value-of select="name(.)"/>
</SPAN>
<SPAN class="m">
<xsl:text>></xsl:text>
</SPAN>
</DIV>
</DIV>
</xsl:template>
<xsl:template match="*[*]" priority="20">
<DIV class="e">
<DIV STYLE="margin-left:1em;text-indent:-2em" class="c">
<A class="b" href="#" false"
<SPAN class="m"><</SPAN>
<SPAN>
<xsl:attribute name="class"><xsl:if test="xsl:*"><xsl:text>x</xsl:text></xsl:if><xsl:text>t</xsl:text></xsl:attribute>
<xsl:value-of select="name(.)"/>
<xsl:if test="@*">
<xsl:text> </xsl:text>
</xsl:if>
</SPAN>
<xsl:apply-templates select="@*"/>
<SPAN class="m">
<xsl:text>></xsl:text>
</SPAN>
</DIV>
<DIV>
<xsl:apply-templates/>
<DIV>
<SPAN class="b">
<xsl:call-template name="entity-ref">
<xsl:with-param name="name">nbsp</xsl:with-param>
</xsl:call-template>
</SPAN>
<SPAN class="m">
<xsl:text></</xsl:text>
</SPAN>
<SPAN>
<xsl:attribute name="class"><xsl:if test="xsl:*"><xsl:text>x</xsl:text></xsl:if><xsl:text>t</xsl:text></xsl:attribute>
<xsl:value-of select="name(.)"/>
</SPAN>
<SPAN class="m">
<xsl:text>></xsl:text>
</SPAN>
</DIV>
</DIV>
</DIV>
</xsl:template>
<xsl:template name="entity-ref">
<xsl:param name="name"/>
<xsl:text disable-output-escaping="yes">&</xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>;</xsl:text>
</xsl:template>
</xsl:stylesheet>
Так же можно попробовать поискать аналогичные default-схемы xsl-преобразований в Сhrome (chrome://global/content/xml/XMLPrettyPrint.xsl) и других броузерах
Желающие могут скачать пример обработки просмотра и форматирования произвольных XML-файлов (управляемые и обычные формы).
Ноо повторяю, что вся автоматизация отображения произволного XML сводится к двум строчкам текста 1С
Преобразование.ЗагрузитьИзСтроки(ТекстПреобразованияXSL);
XML2HTML = Преобразование.ПреобразоватьИзСтроки(ИсходныйТекстXML);
и использованию подходящей XSL-схемы, которую можно найти как в интернете, так и у себя на локальном компьютере.
(0) а такой вариант не подойдет?
Показать
ПросмотрHTML — форма с реквизитом «ДанныеHTML» строкового типа и полем html на форме..
(1) theshadowco,
нет. Это «масло масляное». Подали на вход текст XML в ЗаписьXML.ЗаписатьБезОбработки(ТекстСообщения) и с помощью ЗаписьXML.Закрыть() его же и записали. Ничего не изменилось. И не отобразилось
В статье сразу написано, что
Это — по-моему — и есть
Описанный в статье способ позволяет открыть XML-файл непосредственно в 1С.
Это его единственное преимущество перед открытием в браузере или есть еще достоинства, о коих я не догадался?
(3) gaglo, да, речь идет только о 1С
(4) Ясно. Тогда позволю себе отметить: в публикации infostart.ru/public/21664/двухпальцовый reader_XML , кстати, перечисленной в списке предшественников, есть ссылка на внешний XML-редактор firstobject , маленький (624к), быстрый (файл в 55 мег открывается секунд за 5), портабельный и бесплатный. Да, и он еще позволяет редактировать!
ЗЫ. А ход вашей мысли (то есть выдрать XSL из браузера и применить у себя) мне нравится!
(5) gaglo, Так понятно, что вне 1С есть тысяча и одна удабная утилита для работя с XML. Но ведь я специально указал область задачи: «Внутри 1С и без внешних библиотек». В этом случае все «внешние XML-редакторы» остаются «за бортом»
(6) А вот это мне и непонятно. Зачем специально было так сужать область задачи? Неужели «просто так»? Иными словами, зачем так часто стоит задача отображать XML именно в поле HTML-документа? Если мы хотим XML обработать, так вроде бы отображать и не надо… Навскидку придумал только случай, когда на входе валятся файлы самых разных структур, мы их показываем оператору и спрашиваем: «Чего с ним делать?» А оператор проглядит его, решает, что этот по алгоритму 15, а этот просто отклонить, и нажимает соответствующую кнопку. Но выглядит это неестественно.
(7) gaglo,
http://automediya.ru/ , аналогично тому, как я сделал для Почты России http://infostart.ru/public/347510/
У меня эта задача возникла из разработки интерфейса отслеживания почтовых отправлений различных служб доставки (СДЭК, Деловые линии, ДПД, ПЭК и т.п.) для интернет-магазина
Данные, полученные с с того или ниого вэб-сервиса при этом не требовалось обрабатывать, а только показывать, но в красивом и читаемом виде. Оказалось, что наиболее просто и естественно отобразить их как раз поле HTML-документа
При этом потребовалось обрабатывать исключительные ситуации. А именно, когда код состояния ответа HTML не равен 200. Можно бы было выдать сообщение «КодСостояния=…», но в некотрых случаях в теле ответа приходит содезная информация. Например пришется что-то об ошибке сети, веб-сервиса, прокси и прочее. Вот для таких особых ситуаций универсальный просмотр как раз годится.
Ну а мне еще удобно было им пользоваться при отладке, когда я, в точности как описано выше, имел дело с XML-файлами самих разных структур.
(5) gaglo,
http://infostart.ru/public/84254/
Если уж сравнивать с аналогами не по принципу соответствия поставленной задаче, а про универсальности и простоте, то мне больше чем «двупальцевый» нравится «однопальцевый» вариант
(2) Отлично отображается, вы попробуйте :). Не первый год так работает, отображает любые XML.
Как работает у меня:
Есть регистр с реквизитом, содержащим текст XML. Иногда требуется посмотреть XML в более читабельном виде, чем просто строка. Для Этого на форме записи добавлена указанная в примере команда (точнее выдержка из команды), которая создает временный файл и показывает его в форме просмотре. В этой форме (управляемая) нет ничего интересного, кроме строкового реквизита, которому соответствует элемент формы с видом «Полле HTML документа»
(10) theshadowco,
А что в вашем примере скрыто под конструкцией «ОбщаяФорма.ПросмотрHTML» ?
Давайте вместе посмотрим, что там внутри в этой форме делается
(10) theshadowco,
Надо все-таки смотреть на устройство формы.
По виду снимка вывода можно предположить, что используется OLE-объект
Будет ли Ваша конструкция без переделок работать под Linux?
(12) не используется ничего, только платформа.
Смотрите скрины. Проще некуда.
(13) theshadowco,
Может быть тогда что-то дополнительное установлено в настройках операционной системы и ее интернет-броузерах?
(14) да нет, все по дефолту.
(15) theshadowco,
Я наконец понял, что имелось в виду.
Этот пример действительно работает. Но если все делать через файлы (ЗаписьXML.ОткрытьФайл() вместо ЗаписьXML.УстановитьСтроку()) и полю HTMLДокумента соответственно передавать на вход имя файла на диске, а не текст документа.
Я же говорил о другом, пытался показывать принцип работы с текстом файла, т.е. строковые операции, без привлечения файловой системы
Похоже, что xsl не валидный:
Ошибка разбора XML: — [296,23]
Фатальная ошибка:
Couldn’t find end of Start Tag A line 296
В статье приводиться default.xsl с ошибками. Пример
Тут тег <A> не закрыт. Рабочий XSL скачал от сюдаhttps://gist.github.com/byrner75/5659000 .
А вот не много измененный код:
До сих пор актуально. Фишка с непосредственным подсовывание файла в форму HTML в последних релизах перестала работать.
А «Преобразование» работает. Красота!
Хотел поставить автору плюс, но не буду, т.к. XSL невалиден. Зато поставил плюс (18).