Как получить XML (RAW / SOURCE) из элемента управления WebBrowser - PullRequest
9 голосов
/ 26 мая 2011

Я использую элемент управления WebBrowser в своих тестовых проектах Delphi и .Net C # для перехода к локальному тестовому XML-файлу и пытаюсь сохранить содержимое обратно в XML-файл в .Net DocumentCompleted Event и в Delphi * 1002. * событие.

Проблема в том, что я всегда получаю HTML, который будет преобразован браузером для просмотра (проверьте вывод: я сохранил его, используя следующий код)

procedure TForm1.SaveHTMLSourceToFile(const FileName: string;
  WB: TWebBrowser);
var
  PersistStream: IPersistStreamInit;
  FileStream: TFileStream;
  Stream: IStream;
  SaveResult: HRESULT;
begin
  PersistStream := WB.Document as IPersistStreamInit;
  FileStream := TFileStream.Create(FileName, fmCreate);
  try
    Stream := TStreamAdapter.Create(FileStream, soReference) as IStream;
    SaveResult := PersistStream.Save(Stream, True);
    if FAILED(SaveResult) then
      MessageBox(Handle, 'Fail to save source', 'Error', 0);
  finally
    FileStream.Free;
  end;
end;

Ну, я перепробовал почти все, искал везде, но до сих пор не нашел ничего полезного. С помощью следующего кода Delphi мне удалось показать ИСТОЧНИК, который работает (это означает, что источник находится где-то там), но я не могу его использовать, так как он посеет диалог, и будет нелегко получить данные и закрыть его (в моем тестовом примере Я получаю notepad.exe с моим содержимым xml)

  AWebBrowser.Document.QueryInterface(IOleCommandTarget, CmdTarget) ;
  if CmdTarget <> nil then
  try
    CmdTarget.Exec(PtrGUID, HTMLID_VIEWSOURCE, 0, vaIn, vaOut) ;
  finally
    CmdTarget._Release;
  end;

Мне также удалось вызвать вызов SAVE AS с флагом xxx-HIDE-xxx, но он подключает IE 5, и будет отображаться диалог сохранения как (флаг скрытия будет игнорироваться).

Я также пытался получить XML-данные из кэша (Cache API), но в моем случае я ничего не получил, и 2. что если на компьютере клиента кэширование отключено? ; -)

InnerText или InnerHTML atc. не может использоваться, так как они содержат - и + char и не представляют оригинальные данные RAW (ИСТОЧНИК)

Только для вашей информации: я не могу использовать компоненты WebClient или Indy для доступа к XML. Я также не могу играть в качестве Прокси, так как проблема с открытием портов (скажем, 8080) на клиентской машине мучительна с привилегированным доступом пользователя.

Итак, вот я и спрашиваю вас, есть ли у вас идеи, как решить мою проблему?

Спасибо заранее, Приветствия

ввод:

<?xml version="1.0" encoding="UTF-8"?>
<test><data>xxxx</data></test>

выход:

<HTML><HEAD>
<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>
<SCRIPT><!--
function f(e){
if (e.className=="ci"){if (e.children(0).innerText.indexOf("\n")>0) fix(e,"cb");}
if (e.className=="di"){if (e.children(0).innerText.indexOf("\n")>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;
--></SCRIPT>
</HEAD>
<BODY class="st"><DIV class="e">
<SPAN class="b">&nbsp;</SPAN>
<SPAN class="m">&lt;?</SPAN><SPAN class="pi">xml version="1.0" encoding="UTF-8" </SPAN><SPAN class="m">?&gt;</SPAN>
</DIV>
<DIV class="e">
<DIV class="c" STYLE="margin-left:1em;text-indent:-2em"><A href="#" onclick="return false" onfocus="h()" class="b">-</A>
<SPAN class="m">&lt;</SPAN><SPAN class="t">test</SPAN><SPAN class="m">&gt;</SPAN></DIV>
<DIV><DIV class="e"><DIV STYLE="margin-left:1em;text-indent:-2em">
<SPAN class="b">&nbsp;</SPAN>
<SPAN class="m">&lt;</SPAN><SPAN class="t">data</SPAN><SPAN class="m">&gt;</SPAN><SPAN class="tx">xxxx</SPAN><SPAN class="m">&lt;/</SPAN><SPAN class="t">data</SPAN><SPAN class="m">&gt;</SPAN>
</DIV></DIV>
<DIV><SPAN class="b">&nbsp;</SPAN>
<SPAN class="m">&lt;/</SPAN><SPAN class="t">test</SPAN><SPAN class="m">&gt;</SPAN></DIV>
</DIV></DIV>
</BODY>
</HTML>

Ответы [ 2 ]

4 голосов
/ 29 мая 2011

Вы можете выполнить «теневую» загрузку файла в событии TWebBrowser BeforeNavigate2.
Под тенью я подразумеваю использование процедуры из другой библиотеки для загрузки файла в то же время, когда TWebBrowser загружает его.Таким образом, вы можете получить файл, не изменяя его с помощью TWebBrowser.

Я написал тестовое приложение и все, что мне нужно было сделать, чтобы получить содержимое файла, это

procedure TForm1.WebBrowserBeforeNavigate2(Sender: TObject;
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
  Headers: OleVariant; var Cancel: WordBool);
begin
  HttpGetText(URL,Memo1.Lines);
end;

HttpGetTextфункция блокировки из библиотеки Synapse http://www.ararat.cz/synapse/doku.php/start

Вы также можете использовать ICS, Indy или TDownLoadURL.Обратите внимание, что TDownLoadURL не блокируется, и мне так и не удалось заставить работать его событие AfterDownload.

4 голосов
/ 27 мая 2011

Я думаю, что вы подходите к этому неправильно. Элемент управления TWebBrowser представляет собой визуальный элемент управления, предназначенный для просмотра. Вы можете извлечь из него базовые данные, но, по сути, использование визуального контроля для загрузки чего-либо (невизуальное действие) не является хорошим подходом. Вместо этого вы должны загрузить файл с помощью специального API.

Только для вашей информации: нет способ для меня использовать WebClient или Indy компоненты для доступа к XML. Я также не могу играть в качестве Прокси, так как ...

У вас нет этих компонентов? В этом случае я бы предложил вам использовать любой из следующих подходов:

  1. TDownloadURL - это встроенный класс, полезный для простой загрузки файла. Некоторые примеры его использования:

  2. InternetReadFile . Это то, что я лично использую в своем собственном коде - у меня есть небольшой класс потоков, чтобы асинхронно загружать файлы и уведомлять основной поток, когда они сделаны, реализованные с помощью этой функции. Используйте это:

    • Используйте InternetOpen для инициализации использования интернет-функций; возвращает дескриптор;
    • Используйте этот дескриптор, чтобы получить другой дескриптор, используя InternetOpenUrl , используя INTERNET_FLAG_HYPERLINK or INTERNET_FLAG_NO_UI flags
    • Затем используйте этот дескриптор с InternetReadFile в циклической записи в буфер до тех пор, пока файл не будет прочитан или ваш поток не прерван.
    • Не забудьте закрыть ручки, используя InternetCloseHandle

    Извините, я не могу опубликовать исходный код, но это простые функции, и вы должны найти его достаточно простым для написания.

При этих подходах вы получите либо файл, либо буфер, каждый из которых содержит необработанное содержимое вашего XML-файла.

Редактировать: Я вижу, вы немного объяснили, почему вы не можете использовать Indy:

«Реальный сценарий очень сложный и нужно взаимодействие с пользователем в браузере и после того, как пользователь сделал все Есть несколько постов между браузер и пользователь до конечного результата это файл XML, которого у вас нет контроль, откуда это происходит! "

Я не уверен, что это мешает вам использовать Indy: вместо этого вам просто нужно узнать местоположение этого XML. То, что вы не контролируете, где это, не имеет значения, вам просто нужно выяснить, где это. Либо очистите HTML, если все, что у вас есть, это ссылка (вы уже можете получить HTML из браузера - на самом деле, это ваша проблема!), Либо посмотрите окончательное местоположение, в котором находится документ TWebBrowser, и загрузите его. Другими словами, пусть пользователь делает все, что ему нужно, чтобы перейти к окончательному XML-файлу, но вместо того, чтобы пытаться извлечь его из элемента управления веб-браузера, загрузите его самостоятельно.

...