跳轉到內容

XQuery/解析 CSV

來自華夏公益教科書,開放的書籍,用於開放的世界

您希望將逗號分隔值 (CSV) 文字檔案解析成 XML 結構,或者您有一個具有非常類似行/欄位結構的平面檔案,您希望將其轉換為 XML 格式。

我們將使用 tokenize($input, '\n') 函式將輸入檔案分解成單獨的行。然後,我們將使用 tokenize($input, '\s*,\s*') 函式將每行解析成單獨的欄位。正則表示式 \s* 將刪除空格。

基本示例

[編輯 | 編輯原始碼]
xquery version "1.0";

let $csv-input-sample :=
'John, Smith, x123
Peg, Jones , x456
Sue, Adams , x789
Dan, McCoy , x321'

let $lines := tokenize($csv-input-sample, '\n')

return
<results>{
  for $line in $lines
  let $fields := tokenize($line, '\s*,\s*')
  return
  <row>{
    for $field in $fields
    return
      <field>{$field}</field>
  }</row>
}</results>

執行

示例輸出

[編輯 | 編輯原始碼]
<results>
   <row>
      <field>John</field>
      <field>Smith</field>
      <field>x123</field>
   </row>
   <row>
      <field>Peg</field>
      <field>Jones</field>
      <field>x456</field>
   </row>
   <row>
      <field>Sue</field>
      <field>Adams</field>
      <field>x789</field>
   </row>
   <row>
      <field>Dan</field>
      <field>McCoy</field>
      <field>x321</field>
   </row>
</results>

帶資料字典的示例(第一行)

[編輯 | 編輯原始碼]

第二個示例將使用 CSV 檔案的第一行作為每列的每個元素名稱的資料字典。

xquery version "1.0";

let $csv :=
'name,faculty
alice,anthropology
bob,biology'

let $lines := tokenize($csv, '\n')
let $head := tokenize($lines[1], ',')
let $body := remove($lines, 1)
return
    <people>
        {
            for $line in $body
            let $fields := tokenize($line, ',')
            return
                <person>
                    {
                        for $key at $pos in $head
                        let $value := $fields[$pos]
                        return
                            element { $key } { $value }
                    }
                </person>
        }
    </people>

執行

示例輸出

[編輯 | 編輯原始碼]
<people>
  <person>
    <name>alice</name>
    <faculty>anthropology</faculty>
  </person>
  <person>
    <name>bob</name>
    <faculty>biology</faculty>
  </person>
</people>

新增配置檔案選項

[編輯 | 編輯原始碼]

很多時候,您會有一系列 CSV 檔案,它們可能都具有非常相似的匯入選項。在這種情況下,能夠將一系列配置引數傳遞給單個 XQuery 函式非常有用。這些配置引數包括:

  1. 欄位分隔符是什麼(預設為逗號)
  2. 根節點的元素名稱
  3. 每行或每行的元素名稱
<file-import-config>
   <field-separator>,<field-separator>
   <root-element-name>people</root-element-name>
   <line-element-name>person</line-element-name>
</file-import-config>

然後,您可以在 CSV 解析器中使用此配置檔案。

xquery version "1.0";
let $config := 
<file-import-config>
   <field-separator>:</field-separator>
   <root-element-name>People</root-element-name>
   <line-element-name>Person</line-element-name>
</file-import-config>

let $csv :=
'name:faculty
alice:anthropology
bob:biology'

let $lines := tokenize($csv, '\n')
let $head := tokenize($lines[1], $config/field-separator)
let $body := remove($lines, 1)
return
    element {$config/root-element-name}
        {
            for $line in $body
            let $fields := tokenize($line, $config/field-separator)
            return
                element {$config/line-element-name}
                    {
                        for $key at $pos in $head
                        let $value := $fields[$pos]
                        return
                            element { $key } { $value }
                    }
        }

執行

CSV 複雜性

[編輯 | 編輯原始碼]

上面的程式碼假設了一種簡單的 CSV 格式。在實際應用中,CSV 必須處理更復雜的情況,對於這些情況,簡單的使用 tokeniser() 不足以解析一行。包含一個或多個分隔符的字串將用雙引號括起來。引號內的引號也需要處理。

以下實現處理了部分或全部這些複雜情況,儘管通常不清楚考慮了哪些複雜情況。

[編輯 | 編輯原始碼]
華夏公益教科書