Csv 在XQuery中对字符串进行编码

Csv 在XQuery中对字符串进行编码,csv,xquery,encode,exist-db,Csv,Xquery,Encode,Exist Db,在我的web应用程序中基于eXist db编写了一个函数,用XQuery将一些xml元素导出到csv。一切都很好,但我的元素中有一些umlauts,如u、ä或ß,它们在我的csv中以错误的方式显示。我尝试使用fn:normalizeunicode对内容进行编码,但这不起作用。 以下是我的代码片段的简化示例: let $input = <root> <number>1234</number> <name>Auf

在我的web应用程序中基于eXist db编写了一个函数,用XQuery将一些xml元素导出到csv。一切都很好,但我的元素中有一些umlauts,如u、ä或ß,它们在我的csv中以错误的方式显示。我尝试使用fn:normalizeunicode对内容进行编码,但这不起作用。 以下是我的代码片段的简化示例:

let $input =
    <root>
        <number>1234</number>
        <name>Aufmaß</name>
    </root>

let $csv := string-join(
    for $ta in $input
        return concat($ta/number/text(), fn:normalize-unicode($ta/name/text())))

let $csv-ueber-string := concat($csv-ueber, string-join($massnahmen, $nl))

let $set-content-type := response:set-header('Content-Type', 'text/csv')
let $set-accept := response:set-header('Accept', 'text/csv')
let $set-file-name := response:set-header('Content-Disposition', 'attachment; filename="export.csv"')

return response:stream($csv, '')
let$input=
1234
奥夫马
让$csv:=字符串连接(
在$input中输入$ta
返回concat($ta/number/text(),fn:normalizeunicode($ta/name/text()))
让$csv ueber字符串:=concat($csv ueber,字符串连接($massnahmen,$nl))
let$set content type:=响应:设置标题('content-type','text/csv')
let$set accept:=响应:设置标题('accept','text/csv')
let$set file name:=响应:设置标题('Content-Disposition','attachment;filename=“export.csv”'))
返回响应:流($csv,“”)

您的查询不太可能有任何错误,或者您可以在查询中采取任何措施来纠正此问题

问题可能是

(a) 传递给查询的输入数据采用与查询处理器所认为的不同的字符编码

(b) 查询中的输出数据采用与输出接收者认为的不同的字符编码

快速浏览一下您的查询表明,除了查询源代码本身之外,它实际上没有任何外部输入。但是源代码是输入之一,这可能是错误的来源。消除这种可能性的一个好方法可能是,看看如果更换

<name>Aufmaß</name>
Aufmaß

Aufma{code指向字符串(223)}
如果这解决了问题,那么查询源文本的编码就不是查询编译器认为的编码


另一种可能性是问题出在输出端,坦率地说,这似乎更有可能。您似乎正在生成一个HTTP响应流作为输出,并自己构造HTTP头。我没有看到任何证据表明您正在HTTP响应头中设置任何特定的编码。response:stream()函数是特定于供应商的,我不熟悉它的详细信息,但我怀疑您需要确保它以UTF-8编码内容,并且HTTP头显示它在UTF-8中;这可能是通过函数的额外参数或外部配置选项实现的。

正如您所料,eXist正在将CSV序列化为Unicode(UTF-8)。但是,当您直接在Excel中打开生成的
export.csv
文件(即通过
file>open
)时,Excel将尽力猜测csv文件的编码。但是CSV文件没有任何方式来声明它们的编码,所以应用程序很可能猜错了,就像Excel在您的例子中所做的那样。在我的电脑上,Excel也猜错了,把
Aufmaß
的编码弄乱为
Aufmaß
。下面是强制Excel使用UTF-8编码的CSV文件编码的方法,例如查询生成的文件

  • 在Excel中,通过
    File>new
  • 选择
    File>Import
    以打开一系列对话框,用于指定如何导入CSV文件
  • 在第一个对话框中,选择“CSV文件”作为文件类型
  • 在下一个对话框中,标题为“文本导入向导”- 第1步(共3步),选择“Unicode(UTF-8)”作为“文件来源”(至少这些是我的Mac 2016版MS Excel中的标题/顺序)
  • 继续执行其余对话框,保留默认值
  • 然后Excel将把
    export.csv
    的内容放入新的电子表格中
最后,让我提供以下查询,我用来测试和确认eXist生成的CSV文件在遵循上述说明时是否按预期打开。该查询与您的查询基本相同,但修复了您查询中的一些问题,这些问题使我无法直接运行该查询。我将此查询保存在
/db/csv test.xq
并通过
http://localhost:8080/exist/rest/db/csv-test.xq

xquery version "3.1";

let $input :=
    <root>
        <number>1234</number>
        <name>Aufmaß</name>
    </root>
let $cell-separator := ","
let $column-headings := $input/*/name()
let $header-row := string-join($column-headings, $cell-separator)
let $body-row := string-join($input/*/string(), $cell-separator)
let $newline := '&#10;'
let $csv := string-join(($header-row, $body-row), $newline)
return
    response:stream-binary(
        util:string-to-binary($csv),
        "text/csv", 
        "export.csv"
    )
xquery版本“3.1”;
让$input:=
1234
奥夫马
let$单元格分隔符:=“,”
让$column标题:=$input/*/name()
让$header行:=字符串联接($column headers,$cell separator)
让$body行:=字符串联接($input/*/string(),$cell separator)
让$newline:='
;'
让$csv:=字符串联接($header行,$body行,$newline)
返回
响应:流二进制(
util:字符串到二进制($csv),
“文本/csv”,
“导出.csv”
)

那么您在哪里/如何运行XQuery,如何保存或存储结果,如何查看结果,您希望CSV使用哪种编码?我在基于eXist db的web应用程序中使用XQuery。我使用函数response:stream()存储结果(我已经编辑了我的第一篇文章)。下载csv后,我在Excel中打开它,发现编码并没有真正起作用。嗯,我是字符串编码方面的新手,但utf-8或cp1250应该可以完成这项工作。您可能希望为eXist添加一个标记,因为我确信解决方案的一部分是在这些函数上使用正确的选项或设置,例如
response:set header
response:stream
。eXist的版本是什么?(Martin,我已经按照您的建议添加了eXist标记。)您确定它们没有正确序列化,并且不是文本编辑器吗?像Nodepad这样的编辑器可能会假定它是ASCII。可能需要确保CSV输出被读取为UTF-8。尝试在另一个编辑器中查看,例如Nodepad++?
xquery version "3.1";

let $input :=
    <root>
        <number>1234</number>
        <name>Aufmaß</name>
    </root>
let $cell-separator := ","
let $column-headings := $input/*/name()
let $header-row := string-join($column-headings, $cell-separator)
let $body-row := string-join($input/*/string(), $cell-separator)
let $newline := '&#10;'
let $csv := string-join(($header-row, $body-row), $newline)
return
    response:stream-binary(
        util:string-to-binary($csv),
        "text/csv", 
        "export.csv"
    )