У самого XPath нет способа связать префикс пространства имен с пространством имен. Такие средства предоставляются библиотекой хостинга.
Рекомендуется использовать эти средства и определять префиксы пространства имен, которые затем могут использоваться для квалифицирования XML-элементов и имен атрибутов по мере необходимости.
Вот некоторые из различных механизмов, которые хосты XPath предоставляют для указания привязок префикса пространства имен к URI пространства имен:
XSLT:
...
Perl ( LibXML ):
my $xc = XML::LibXML::XPathContext->new($doc);
$xc->registerNs('i', 'http://schema.intuit.com/finance/v3');
my @nodes = $xc->findnodes('/i:IntuitResponse/i:QueryResponse');
Python ( lxml ):
from lxml import etree
f = StringIO('... ')
doc = etree.parse(f)
r = doc.xpath('/i:IntuitResponse/i:QueryResponse',
namespaces={'i':'http://schema.intuit.com/finance/v3'})
Python ( ElementTree ):
namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)
Java (SAX):
NamespaceSupport support = new NamespaceSupport();
support.pushContext();
support.declarePrefix("i", "http://schema.intuit.com/finance/v3");
Java (XPath):
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
switch (prefix) {
case "i": return "http://schema.intuit.com/finance/v3";
// ...
}
});
DocumentBuilderFactory.setNamespaceAware(true)
.C #:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
XmlNodeList nodes = el.SelectNodes(@"/i:IntuitResponse/i:QueryResponse", nsmgr);
xmlstarlet:
-N i="http://schema.intuit.com/finance/v3"
JavaScript:
См. Реализация разрешенного пользователем пространства имен Resolver :
function nsResolver(prefix) {
var ns = {
'i' : 'http://schema.intuit.com/finance/v3'
};
return ns[prefix] || null;
}
document.evaluate( '/i:IntuitResponse/i:QueryResponse',
document, nsResolver, XPathResult.ANY_TYPE,
null );
PhP :
Адаптировано из @ ответа Томалака с использованием DOMDocument :
$result = new DOMDocument();
$result->loadXML($xml);
$xpath = new DOMXpath($result);
$xpath->registerNamespace("i", "http://schema.intuit.com/finance/v3");
$result = $xpath->query("/i:IntuitResponse/i:QueryResponse");
См. также @ Канонический Q / A IMSoP на PHP Пространства имен SimpleXML .
VBA:
xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'"
doc.setProperty "SelectionNamespaces", xmlNS
Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse")
Как только вы объявили префикс пространства имен, ваш XPath можно записать, чтобы использовать его:
/i:IntuitResponse/i:QueryResponse
Альтернативой является запись предикатов, которые проверяют на local-name()
:
/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition
Или, в XPath 2.0:
/*:IntuitResponse/*:QueryResponse/@startPosition
Пространство имен в этом стиле работает, но не рекомендуется, потому что оно
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='IntuitResponse']
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='QueryResponse']
/@startPosition
1Подается Даниэль Хейли для примечания namespace-uri()
. В Rails я делаю так:
function download_file(file_id) {
let url = '/files/' + file_id + '/download_file';
$.ajax({
type: 'GET',
url: url,
processData: false,
success: function (data) {
window.location = url;
},
error: function (xhr) {
console.log(' Error: >>>> ' + JSON.stringify(xhr));
}
});
}
Трюк - это часть window.location . Метод контроллера выглядит так:
# GET /files/{:id}/download_file/
def download_file
send_file(@file.file,
:disposition => 'attachment',
:url_based_filename => false)
end
Вот что я сделал, чистый javascript и html. Не тестировал, но это должно работать во всех браузерах.
Функция Javascript
blockquote>var iframe = document.createElement('iframe'); iframe.id = "IFRAMEID"; iframe.style.display = 'none'; document.body.appendChild(iframe); iframe.src = 'SERVERURL'+'?' + $.param($scope.filtro); iframe.addEventListener("load", function () { console.log("FILE LOAD DONE.. Download should start now"); });
Использование только компонентов, поддерживаемых во всех браузерах нет дополнительных библиотек.
blockquote>[/g0] [/g1]
Вот код контроллера JAVA Spring на стороне сервера.
blockquote>@RequestMapping(value = "/rootto/my/xlsx", method = RequestMethod.GET) public void downloadExcelFile(@RequestParam(value = "param1", required = false) String param1, HttpServletRequest request, HttpServletResponse response) throws ParseException { Workbook wb = service.getWorkbook(param1); if (wb != null) { try { String fileName = "myfile_" + sdf.format(new Date()); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + ".xlsx\""); wb.write(response.getOutputStream()); response.getOutputStream().close(); } catch (IOException e) { e.printStackTrace(); } } }
Если вы хотите использовать загрузку файла jQuery, обратите внимание на это для IE. Вам нужно сбросить ответ или он не будет загружен
//The IE will only work if you reset response
getServletResponse().reset();
//The jquery.fileDownload needs a cookie be set
getServletResponse().setHeader("Set-Cookie", "fileDownload=true; path=/");
//Do the reset of your action create InputStream and return
. Ваше действие может реализовать ServletResponseAware
для доступа к getServletResponse()
Уверен, что вы не можете сделать это через вызов Ajax.
Однако существует обходное решение.
Шаги:
Если вы используете form.submit () для загрузки файла, что вы можете сделать:
Это полезно в том случае, если вы хотите решить, не нужно загружать файл после создания form.submit (), например: может быть случай, когда в form.submit () исключение возникает на стороне сервера и вместо сбоя может потребоваться показать пользовательское сообщение на клиентская сторона, в этом случае эта реализация может помочь.
Добавляем еще несколько вещей для ответа на этот вопрос для загрузки файла
Ниже приведен код java spring, который генерирует байт Array
@RequestMapping(value = "/downloadReport", method = { RequestMethod.POST })
public ResponseEntity<byte[]> downloadReport(
@RequestBody final SomeObejct obj, HttpServletResponse response) throws Exception {
OutputStream out = new ByteArrayOutputStream();
// write something to output stream
HttpHeaders respHeaders = new HttpHeaders();
respHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
respHeaders.add("X-File-Name", name);
ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
return new ResponseEntity<byte[]>(bos.toByteArray(), respHeaders, HttpStatus.CREATED);
}
Теперь в javascript-коде с использованием FileSaver.js, можно загрузить файл с кодом ниже
var json=angular.toJson("somejsobject");
var url=apiEndPoint+'some url';
var xhr = new XMLHttpRequest();
//headers('X-File-Name')
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 201) {
var res = this.response;
var fileName=this.getResponseHeader('X-File-Name');
var data = new Blob([res]);
saveAs(data, fileName); //this from FileSaver.js
}
}
xhr.open('POST', url);
xhr.setRequestHeader('Authorization','Bearer ' + token);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'arraybuffer';
xhr.send(json);
Вышеупомянутый файл будет загружен
Никто не отправил это @ решение Пекки ... поэтому я опубликую его. Это может помочь кому-то.
Вы не можете и не должны делать это через Ajax. Просто используйте
window.location="download.action?para1=value1...."
window.open(<url>, '_blank');
, чтобы гарантировать, что загрузка не заменит ваш текущий контент браузера (независимо от заголовка Content-Disposition).
– Christopher King
15 August 2014 в 16:38
a
в dom, чтобы этот код работал и / или удалял часть revokeObjectURL
: document.body.appendChild(a)
– ssostalker
14 November 2017 в 22:26
Простой способ заставить браузер загружать файл - это сделать такой запрос:
function downloadFile(urlToSend) {
var req = new XMLHttpRequest();
req.open("GET", urlToSend, true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download=fileName;
link.click();
};
req.send();
}
Это открывает всплывающее окно браузера.
Я нашел исправление, что, хотя на самом деле он не использует ajax, он позволяет вам использовать вызов javascript для запроса загрузки, а затем получить обратный вызов, когда загрузка начнется. Я нашел это полезным, если ссылка запускает скрипт на стороне сервера, который занимает немного времени, чтобы составить файл перед его отправкой. поэтому вы можете предупредить их о том, что он обрабатывается, а затем, когда он наконец отправит файл, удалите это уведомление об обработке. поэтому я хотел попытаться загрузить файл через ajax, чтобы начать с того, что я мог бы иметь событие, когда файл запрашивается, а другой, когда он действительно начинает загружаться.
js на первой странице
function expdone()
{
document.getElementById('exportdiv').style.display='none';
}
function expgo()
{
document.getElementById('exportdiv').style.display='block';
document.getElementById('exportif').src='test2.php?arguments=data';
}
iframe
<div id="exportdiv" style="display:none;">
<img src="loader.gif"><br><h1>Generating Report</h1>
<iframe id="exportif" src="" style="width: 1px;height: 1px; border:0px;"></iframe>
</div>
, а затем другой файл:
<!DOCTYPE html>
<html>
<head>
<script>
function expdone()
{
window.parent.expdone();
}
</script>
</head>
<body>
<iframe id="exportif" src="<?php echo "http://10.192.37.211/npdtracker/exportthismonth.php?arguments=".$_GET["arguments"]; ?>"></iframe>
<script>document.getElementById('exportif').onload= expdone;</script>
</body></html>
Я думаю, что есть способ прочитать данные с помощью js, чтобы потом php не понадобится. но я не знаю, это от руки, а сервер, который я использую, поддерживает php, поэтому это работает для меня. подумал, что я поделюсь им, если он кому-то поможет.
Я столкнулся с той же проблемой и успешно ее разрешил.
«Опубликовать данные JSON на сервере и получить файл excel. Этот файл excel создается сервером и возвращается как ответ клиенту. Загрузите этот ответ в виде файла с пользовательским именем в браузере "
$("#my-button").on("click", function(){
// Data to post
data = {
ids: [1, 2, 3, 4, 5]
};
// Use XMLHttpRequest instead of Jquery $ajax
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
var a;
if (xhttp.readyState === 4 && xhttp.status === 200) {
// Trick for making downloadable link
a = document.createElement('a');
a.href = window.URL.createObjectURL(xhttp.response);
// Give filename you wish to download
a.download = "test-file.xls";
a.style.display = 'none';
document.body.appendChild(a);
a.click();
}
};
// Post data to URL which handles post request
xhttp.open("POST", excelDownloadUrl);
xhttp.setRequestHeader("Content-Type", "application/json");
// You should set responseType as blob for binary responses
xhttp.responseType = 'blob';
xhttp.send(JSON.stringify(data));
});
Вышеприведенный фрагмент просто выполняет следующие действия
Здесь нам нужно тщательно установить несколько вещей на стороне сервера. Я установил несколько заголовков в Python Django HttpResponse. Вы должны установить их соответственно, если используете другие языки программирования.
# In python django code
response = HttpResponse(file_content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
Так как я загружаю xls (excel) здесь, я скорректировал contentType на один. Вам нужно установить его в соответствии с типом файла. Вы можете использовать эту технику для загрузки любых файлов.
Я создал небольшую функцию в качестве решения обхода (вдохновленный плагином @JohnCulviner):
// creates iframe and form in it with hidden field,
// then submit form with provided data
// url - form url
// data - data to form field
// input_name - form hidden input name
function ajax_download(url, data, input_name) {
var $iframe,
iframe_doc,
iframe_html;
if (($iframe = $('#download_iframe')).length === 0) {
$iframe = $("<iframe id='download_iframe'" +
" style='display: none' src='about:blank'></iframe>"
).appendTo("body");
}
iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
if (iframe_doc.document) {
iframe_doc = iframe_doc.document;
}
iframe_html = "<html><head></head><body><form method='POST' action='" +
url +"'>" +
"<input type=hidden name='" + input_name + "' value='" +
JSON.stringify(data) +"'/></form>" +
"</body></html>";
iframe_doc.open();
iframe_doc.write(iframe_html);
$(iframe_doc).find('form').submit();
}
Демо с событием click:
$('#someid').on('click', function() {
ajax_download('/download.action', {'para1': 1, 'para2': 2}, 'dataname');
});
Хорошо, на основе кода ndpu, это улучшенная (я думаю) версия ajax_download; -
function ajax_download(url, data) {
var $iframe,
iframe_doc,
iframe_html;
if (($iframe = $('#download_iframe')).length === 0) {
$iframe = $("<iframe id='download_iframe'" +
" style='display: none' src='about:blank'></iframe>"
).appendTo("body");
}
iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
if (iframe_doc.document) {
iframe_doc = iframe_doc.document;
}
iframe_html = "<html><head></head><body><form method='POST' action='" +
url +"'>"
Object.keys(data).forEach(function(key){
iframe_html += "<input type='hidden' name='"+key+"' value='"+data[key]+"'>";
});
iframe_html +="</form></body></html>";
iframe_doc.open();
iframe_doc.write(iframe_html);
$(iframe_doc).find('form').submit();
}
Используйте это следующим образом: -
$('#someid').on('click', function() {
ajax_download('/download.action', {'para1': 1, 'para2': 2});
});
Параметры отправлены как правильные пост-параметры, как если бы они поступали из ввода, а не как json-кодированная строка в соответствии с предыдущим примером.
CAVEAT: Будьте осторожны в отношении возможности для переменной инъекции в этих формах. Может быть более безопасный способ кодирования этих переменных. Альтернативно созерцайте их.
Uncaught SecurityError: Blocked a frame with origin "http://foo.bar.com" from accessing a frame with origin "null". The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "data". Protocols must match.
– void
16 January 2016 в 11:09
@ResourceMapping() public void downloadFile(final ResourceRequest request, final ResourceResponse response, @ModelAttribute("downForm") FormModel model)
, но он не работает.
– bartex9
12 January 2017 в 10:23
function downloadURI(uri, name)
{
var link = document.createElement("a");
link.download = name;
link.href = uri;
link.click();
}
download
, поэтому ваш файл будет иметь имя & quot; Неизвестно & quot;
– Yangshun Tay
16 May 2016 в 09:21
Итак, вот рабочий код при использовании MVC, и вы получаете свой файл с контроллера
, предположим, что ваш массив байтов объявляется и заполняется, единственное, что вам нужно сделать, это использовать функцию File (используя System.Web.Mvc)
byte[] bytes = .... insert your bytes in the array
return File(bytes, System.Net.Mime.MediaTypeNames.Application.Octet, "nameoffile.exe");
, а затем в том же контроллере добавьте thoses 2 функции
protected override void OnResultExecuting(ResultExecutingContext context)
{
CheckAndHandleFileResult(context);
base.OnResultExecuting(context);
}
private const string FILE_DOWNLOAD_COOKIE_NAME = "fileDownload";
/// <summary>
/// If the current response is a FileResult (an MVC base class for files) then write a
/// cookie to inform jquery.fileDownload that a successful file download has occured
/// </summary>
/// <param name="context"></param>
private void CheckAndHandleFileResult(ResultExecutingContext context)
{
if (context.Result is FileResult)
//jquery.fileDownload uses this cookie to determine that a file download has completed successfully
Response.SetCookie(new HttpCookie(FILE_DOWNLOAD_COOKIE_NAME, "true") { Path = "/" });
else
//ensure that the cookie is removed in case someone did a file download without using jquery.fileDownload
if (Request.Cookies[FILE_DOWNLOAD_COOKIE_NAME] != null)
Response.Cookies[FILE_DOWNLOAD_COOKIE_NAME].Expires = DateTime.Now.AddYears(-1);
}
, после чего вы сможете вызовите своего контроллера для загрузки и получите обратный вызов «успех» или «отказ»
$.fileDownload(mvcUrl('name of the controller'), {
httpMethod: 'POST',
successCallback: function (url) {
//insert success code
},
failCallback: function (html, url) {
//insert fail code
}
});