2011-05-26 14 views
9

Uso el control WebBrowser en mis proyectos de prueba Delphi y .Net C# para navegar a un archivo XML de prueba local y tratar de guardar el contenido en un XML archivo en .Net DocumentCompleted Evento y en Delphi onNavigateComple2 evento.Cómo obtener XML (RAW/SOURCE) desde un control WebBrowser

El problema es que siempre me dan HTML que será transformada por el navegador para la visualización (revisar mi salida: Me salvó de que con el uso el siguiente código)

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; 

Bueno, he intentado casi todo, buscado en todas partes, pero hasta ahora no podía encontrar nada útil. Con el siguiente código Delphi he manejado para mostrar el SOURCE que funciona (Eso significa que la fuente está en algún lugar) pero no puedo usar esto ya que sembrará un diálogo y no será fácil obtener los datos y cerrar ese diálogo (en mi caso de prueba) me da la notepad.exe con mi contenido XML)

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

también logré llamar la llamada SAVE AS con la bandera xxx-xxx-Hide, pero las costuras hasta el 5 IE guardar como se mostrará el diálogo (la bandera oculta será ignorada).

También traté de obtener los datos XML de la memoria caché (API de la memoria caché), pero en mi caso no obtendré nada 2. ¿Qué pasa si en la máquina del cliente la memoria caché está deshabilitada? ;-)

InnerText o InnerHTML atc. no se puede utilizar, ya que contienen - y + char y no representan los datos RAW origniales (SOURCE)

Solo para su información: No hay forma de que use los componentes WebClient o Indy para acceder al xml. Tampoco puedo jugar como un Proxy ya que el problema con la apertura de los puertos (digamos 8080) en la máquina de los clientes es doloroso con el acceso privilegiado de los usuarios.

Así que aquí estoy y preguntando si tienes alguna idea de cómo resolver mi problema?

Gracias de antemano, Saludos

de entrada:

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

de salida:

<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> 
+0

Espera - * ¿por qué * no puedes simplemente descargar el archivo directamente con WebClient o Indy? Ciertamente parece que esos deberían ser más simples que involucrar un gran control de UI. –

+0

bueno, eso es solo una muestra que publiqué aquí. Escribí esa prueba xml/aplicación de prueba. El escenario real es muy complejo y necesita interacción del usuario en el navegador y después de que el usuario hizo todo, hay algunas publicaciones entre el navegador y el usuario hasta que el resultado final es un archivo XML que no tiene control sobre el origen. ¡Es por eso! – Gohlool

Respuesta

4

Creo que se está acercando a mal. Un control TWebBrowser es un control visual destinado a ser visto. Es posible que pueda extraer los datos subyacentes de él, pero fundamentalmente, usar control visual para descargar algo (una acción no visual) no es un buen enfoque. En su lugar, debe descargar el archivo utilizando una API dedicada.

Sólo para su información: No hay manera para que yo use cliente Web o Indy componentes para acceder al XML. Yo también no puedo jugar como un Proxy desde ...

¿No tiene esos componentes? En ese caso, me gustaría sugerir que utiliza cualquiera de los siguientes enfoques:

  1. TDownloadURL es una clase A integrado, útil para facilitar la descarga de un archivo.Algunos ejemplos de su uso:

  2. InternetReadFile. Esto es lo que yo personalmente uso en mi propio código: tengo una pequeña clase de subprocesos para descargar archivos de forma asíncrona y notificar al hilo principal cuando terminan, implementado con esta función. Úselo por:

    • Use InternetOpen para inicializar el uso de las funciones de internet; devuelve un mango;
    • uso que se encargan de conseguir otro mango con InternetOpenUrl usando las banderas INTERNET_FLAG_HYPERLINK or INTERNET_FLAG_NO_UI
    • luego usar ese mango con InternetReadFile en un escrito de bucle en una memoria intermedia hasta que el archivo se lee o se termina el hilo.
    • No se olvide de cerrar las asas utilizando InternetCloseHandle

    Lo siento, no se puede publicar el código fuente, pero son funciones simples y debería buscar que sea bastante fácil de escribir.

Estos métodos obtendrán un archivo o un búfer, cada uno con el contenido sin formato de su archivo XML.

Editar: veo que explicó un poco acerca de por qué no se puede utilizar Indy:

"El escenario real es mucho más compleja y la interacción del usuario necesidad en el navegador y después de que el usuario hizo todo hay algunas publicaciones entre navegador y usuario hasta el resultado final es un archivo XML que no tiene control de dónde viene. "

No estoy seguro de que esto te impida usar Indy: en su lugar, solo necesitas obtener la ubicación de este XML. No importa el hecho de que no controle dónde está, solo necesita averiguar dónde está. O raspe el HTML si todo lo que tiene es un enlace (ya puede obtener HTML del navegador, de hecho, ese es su problema) o mire la ubicación final en la que se encuentra el documento TWebBrowser, y descárguelo. En otras palabras, permita que el usuario haga lo que tenga que hacer para navegar hasta el archivo XML final, pero en lugar de tratar de extraerlo del control del navegador web, descárguelo usted mismo.

+0

Gracias amigo por tu comentario y tratando de señalar otro enfoque! ¡Conozco cada llamada y método que ustedes escribieron aquí! ¡No hay forma de que yo sepa cuál es la URL final! El resultado (respuesta) del servidor se basa en la entrada/acción del usuario, que se maneja mediante el inicio de sesión y la autenticación, y al ingresar un PIN para la acción principal. Eso significa que el usuario ingresa un PIN en la web: desde (publicar en el servidor), para lo cual se generará una respuesta (nunca la misma y la respuesta exacta) en la entrada del PIN. – Gohlool

+0

@Gohlool: ¿estás seguro de que "no hay forma ... de saber cuál es la URL final"? ¿No puede ver a dónde está navegando el navegador web, utilizando uno de sus eventos de navegación? –

4

Puede realizar una descarga "oculta" del archivo en el evento TExbrowser BeforeNavigate2.
Por sombra, me refiero a utilizar un procedimiento de otra biblioteca para descargar el archivo al mismo tiempo que TWebBrowser lo está descargando. De esta forma, puede obtener el archivo sin que TWebBrowser lo modifique.

escribí una aplicación de prueba y todo lo que tenía que hacer las obtener el contenido del archivo es

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

El HttpGetText es una función de bloqueo de la biblioteca Synapse http://www.ararat.cz/synapse/doku.php/start

También es posible usar ICS, Indy , o TDownLoadURL. Tenga en cuenta que TDownLoadURL no está bloqueando y nunca pude hacer que funcione su evento AfterDownload.

+0

¡Gracias! ¡Muy buena idea! pero ... bueno, eso funcionó para mi muestra anterior pero no en mi aplicación real en combinación con el servidor. ;-(pero recibe un voto mío! ;-) – Gohlool

+0

@ Gohlool- Mi enfoque supone que hay un enlace al archivo XML en la página que muestra TWebBrowser, y el usuario hace clic en él. De su respuesta, tengo que asumir que ese no es su caso. Entonces mi pregunta es: ¿cómo sabes que el archivo XML está listo para ser descargado y cómo se obtiene su dirección? – crefird

Cuestiones relacionadas