【问题标题】:XML to CSV conversion using XQuery使用 XQuery 将 XML 转换为 CSV
【发布时间】:2012-12-30 06:46:37
【问题描述】:

我有一个 XML 文件,我需要将它转换成 XQuery。考虑一组简单的 XML:

books[book]
book[@isbn, title, descrption]

例如:

<books>
    <book isbn="1590593049">
        <title>Extending Flash MX 2004</title>
        <description>
        Using javascript alongwith actionscript 3.0 and mxml.</description>
    </book>
    <book isbn="0132149184">
        <title>Java Software Solutions</title>
        <description>
            Complete book full of case studies on business solutions and design concepts while building mission critical
            business applications.
        </description>
    </book>

如何使用 XQuery 将其转换为 CSV 格式? CSV 被 Microsoft excel 使用,

所以它会用逗号(,)字符分隔,特殊字符应该转义。

【问题讨论】:

    标签: xml xquery marklogic xpath-2.0 altova


    【解决方案1】:

    纯 XPath 2.0 表达式

    for $b in /*/book
        return
          concat(escape-html-uri(string-join(($b/@isbn,
                                              $b/title,
                                              $b/description
                                              )
                                               /normalize-space(),
                                            ",")
                                 ),
                 codepoints-to-string(10))
    

    基于 XSLT 2 的验证:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="/">
      <xsl:sequence select=
       "for $b in /*/book
           return
             concat(escape-html-uri(string-join(($b/@isbn,
                                                 $b/title,
                                                 $b/description
                                                 )
                                                  /normalize-space(),
                                               ',')
                                    ),
                    codepoints-to-string(10))"/>
     </xsl:template>
    </xsl:stylesheet>
    

    当此转换应用于所提供的 XML 文档时(已纠正其格式错误):

    <books>
        <book isbn="1590593049">
            <title>Extending Flash MX 2004</title>
            <description>
            Using javascript alongwith actionscript 3.0 and mxml.</description>
        </book>
        <book isbn="0132149184">
            <title>Java Software Solutions</title>
            <description>
                Complete book full of case studies on business solutions and design concepts while building mission critical
                business applications.
            </description>
        </book>
    </books>
    

    产生想要的正确结果

    1590593049,Extending Flash MX 2004,Using javascript alongwith actionscript 3.0 and mxml.
     0132149184,Java Software Solutions,Complete book full of case studies on business solutions and design concepts while building mission critical business applications.
    

    更新

    在评论中,OP 要求任何文本中的逗号都用引号括起来,并且(之后)任何引号都被两个引号替换,最后,如果整个结果包含一个引号,它必须是用(单)引号括起来。

    下面是一个纯 XPath 2.0 表达式,它产生了这个:

    for $b in /*/book,
        $q in codepoints-to-string(34),
        $NL in codepoints-to-string(10),
        $isbn in normalize-space(replace($b/@isbn, ',', concat($q,',',$q))),
        $t in normalize-space(replace($b/title, ',', concat($q,',',$q))),
        $d in normalize-space(replace($b/description, ',', concat($q,',',$q))),
        $res in
         escape-html-uri(string-join(($isbn,$t,$d), ',')),
        $res2 in replace($res, $q, concat($q,$q))
       return
        if(contains($res2, $q))
           then concat($q, $res2, $q, $NL)
           else concat($res2, $NL)
    

    当此 XPath 表达式针对此(使用新的测试用例扩展)XML 文档进行评估时:

    <books>
        <book isbn="1590593049">
            <title>Extending Flash MX 2004</title>
            <description>
            Using javascript alongwith actionscript 3.0 and mxml.</description>
        </book>
        <book isbn="0132149184">
            <title>Java Software Solutions</title>
            <description>
                Complete book full of case studies on business solutions and design concepts while building mission critical
                business applications.
            </description>
        </book>
        <book isbn="XX1234567">
            <title>Quotes and comma</title>
            <description>
                Hello, World from "Ms-Excel"
            </description>
        </book>
    </books>
    

    产生了想要的正确结果:

    1590593049,Extending Flash MX 2004,Using javascript alongwith actionscript 3.0 and mxml.
    0132149184,Java Software Solutions,Complete book full of case studies on business solutions and design concepts while building mission critical business applications.
    "XX1234567,Quotes and comma,Hello"","" World from ""Ms-Excel"""
    

    【讨论】:

    • 但如果它是纯 XPath 2,它不会解释 ' '作为换行符
    • @BeniBela,您的问题不清楚——我用使用相同 XPath 表达式的 XSLT 转换更新了我的答案。如果这不是合法的 XPath 表达式,则会出现错误,但转换工作没有任何问题。
    • 好吧,如果将它包含在 XSLT 中,它就不再是 XPath。然后 XML 解析器替换 。如果您只运行没有 XSLT 的 pure XPath,您会得到:示例中的 1590593049,Extending Flash MX 2004,Using javascript alongwith actionscript 3.0 and mxml.&amp;#xa; 0132149184,Java Software Solutions,Complete book full of case studies on business solutions and design concepts while building mission critical business applications.&amp;#xa;
    • @BeniBela,你可能是对的。我想知道为什么 XQuery 处理器会识别字符引用...当然,要纠正注意到的问题,只需将 &amp;#xa; 替换为 codepoints-to-string(10)
    • @DimitreNovaatchev,您发布的上述 sn-p 在正常情况下效果很好,但在 CSV 中,字段由逗号(,)分隔。现在,如果文本本身包含逗号,那么当逗号是文本的一部分时,excel 会将该逗号解释为分隔符,例如,描述单元格或标题单元格的一部分。一种典型的方法是,通过包裹双引号 (") 来转义逗号,并通过在双引号之前添加双引号来转义双引号: Hello, World from "Ms-Excel" 将是: "Hello, World from ""Ms-Excel """。这样怎么逃?谢谢你的大力帮助。
    【解决方案2】:

    假设您的 xml 位于变量 $books 中,您可以使用以下命令创建一个 csv 文件,其中每个书节点位于新行上:

    declare function local:my-replace($input) {
      for $i in $input
      return '"' || replace($i, '"', '""') || '"'
    };
    for $book in $books//book
    return string-join(local:my-replace(($book/@isbn, $book/title, $book/description)), ",") || '&#xa;'
    

    string-join 连接不同的字符串,本地函数my-replace 根据您的规范替换序列中的值。

    【讨论】:

    • 您发布的上述 sn-p 在正常情况下效果很好,但在 CSV 中,字段由逗号(,)分隔。现在,如果文本本身包含逗号,那么当逗号是文本的一部分时,excel 会将该逗号解释为分隔符,例如,描述单元格或标题单元格的一部分。一种典型的方法是,通过包裹双引号 (") 来转义逗号,并通过在双引号之前添加双引号来转义双引号: Hello, World from "Ms-Excel" 将是: "Hello, World from ""Ms-Excel """。这样怎么逃?谢谢你的大力帮助。
    • 我刚刚编辑了我的答案以反映您添加的规范。我刚刚创建了一个用户定义的函数 my-replace,它在每个元素的开头和结尾添加一个 ",并将 " 替换为 "。
    猜你喜欢
    • 2020-10-20
    • 2023-03-07
    • 1970-01-01
    • 2019-02-02
    • 2017-05-23
    • 2011-10-28
    • 2017-12-14
    相关资源
    最近更新 更多