【问题标题】:How to embed a CSV file in XML output如何在 XML 输出中嵌入 CSV 文件
【发布时间】:2019-06-10 09:13:46
【问题描述】:

我正在尝试使用 XSLT 将 CSV(逗号分隔文件)转换为 XML。

CSV 示例:

AcctEntryId,ValueDate,Entity,Folder,DenomCcy,FunctCcy
321,2017-08-29,ABC NY,My Portfolio/PAC,BR,US
322,2017-08-30,ABC NY,My Portfolio/PBC,BR,US
323,2017-08-31,ABC NY,My Portfolio/PCC,BR,US

所需的 XML 输出:

<?xml version="1.0" encoding="utf-8"?>
<ProcessResponse xmlns="http://com.test.ws/">
    <ProcessResult>&lt;Data DataNodeName="CData" DataType="TEXT"&gt;&lt;CData&gt;&lt;![CDATA[AcctEntryId,ValueDate,Entity,Folder,DenomCcy,FunctCcy
        321,2017-08-29,ABC NY,My Portfolio/PAC,BR,US
        322,2017-08-30,ABC NY,My Portfolio/PBC,BR,US
        323,2017-08-31,ABC NY,My Portfolio/PCC,BR,US
        ]]&gt;&lt;/CData&gt;&lt;/Data&gt;
    </ProcessResult>
</ProcessResponse>

我想从 sap 的 AL11 文件夹中选择 CSV 文件。 xslt 映射后的最终输出,我希望它是上面指定的所需格式的 XML 文件。

请您指导我如何编写 XSLT 代码以根据示例 CSV 数据生成上述 XML。

【问题讨论】:

  • XSLT 仅转换 XML 内容。您上面描述的输入只是 CSV 格式的文本。你会使用什么脚本语言来转换它?

标签: xml csv xslt sap


【解决方案1】:

这是将 CSV 转换为 XML 没有 XSLT 的方法。所需的 XML 相当原始,因为它只有一个子节点,所以我认为 XSLT 在这里是多余的。

DATA: lv_data     TYPE string,
      lv_filename TYPE string VALUE 'C:\usr\sap\erp\sys\src\sample.csv',
      lv_csv      TYPE string.

OPEN DATASET lv_filename FOR INPUT IN TEXT MODE ENCODING DEFAULT.

WHILE sy-subrc = 0.
READ DATASET lv_filename INTO lv_data.
CHECK strlen( lv_data ) > 0.
lv_csv = lv_csv && lv_data && cl_abap_char_utilities=>cr_lf.
NDWHILE.
CLOSE DATASET lv_filename.

DATA(lo_ixml) = cl_ixml=>create( ).
DATA(lo_response) = lo_ixml->create_document( ).
DATA(lo_result)  = lo_response->create_simple_element( name    = 'ProcessResponse' parent  = lo_response ).

CONCATENATE `&lt;Data DataNodeName="CData" DataType="TEXT"&gt;&lt;CData&gt;&lt;![CDATA[`
v_csv `]]&gt;&lt;/CData&gt;&lt;/Data&gt;` INTO lv_csv.

o_response->create_simple_element( name    = 'ProcessResult' parent  = lo_result value   = lv_csv ).

DATA(lo_streamfactory) = lo_ixml->create_stream_factory( ).
DATA(lo_ostream)  = lo_streamfactory->create_ostream_uri( system_id = 'C:\usr\sap\erp\sys\src\sample.xml' ).
DATA(lo_renderer) = lo_ixml->create_renderer( ostream  = lo_ostream document = lo_response ).
DATA(ref_ixml_encoding) = lo_ixml->create_encoding( byte_order    = 0 character_set = 'UTF-8' ).

o_ostream->set_encoding( encoding = ref_ixml_encoding ).
o_ostream->set_pretty_print( 'X' ).
o_renderer->render( ).

只要您的 CSV 位于C:\usr\sap\erp\sys\src\ 目录中,只需运行此 sn-p,生成的 XML 将放在同一目录中。

【讨论】:

    【解决方案2】:

    这是一个 XSLT-2.0 或更高版本的解决方案。我不知道 SAP 是否支持这一点。如果没有,请参阅下面的 XSLT-1.0 hack。

    您可以将 XSLT-2.0 函数 unparsed-text()xsl:analyze-string 的 RegEx 功能结合使用:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:variable name="csv" select="replace(unparsed-text('file:///home/kubuntu/Downloads/a.csv'),'utf-8','')"/>
    
        <xsl:template match="/">
            <xsl:element name="ProcessResponse" namespace="http://com.test.ws/">
                <xsl:element name="ProcessResult" namespace="http://com.test.ws/">
                    <xsl:value-of select="'&lt;Data DataNodeName=&quot;CData&quot; DataType=&quot;TEXT&quot;&gt;&lt;CData&gt;&lt;![CDATA['" />
                    <xsl:analyze-string select="$csv" regex='(.+)\n'>
                        <xsl:matching-substring>
                            <xsl:value-of select="concat(regex-group(1),'&#xa;')" />
                        </xsl:matching-substring>
                        <xsl:non-matching-substring><xsl:sequence select="."/></xsl:non-matching-substring>
                    </xsl:analyze-string>
                    <xsl:value-of select="']]&gt;&lt;/CData&gt;&lt;/Data&gt;&#xa;'" />
                </xsl:element>
            </xsl:element>
        </xsl:template>
    
    </xsl:stylesheet>
    

    输出符合预期,虽然它的要求对我来说似乎有点奇怪......

    <?xml version="1.0" encoding="UTF-8"?>
    <ProcessResponse xmlns="http://com.test.ws/">
       <ProcessResult>&lt;Data DataNodeName="CData" DataType="TEXT"&gt;&lt;CData&gt;&lt;![CDATA[AcctEntryId,ValueDate,Entity,Folder,DenomCcy,FunctCcy
    321,2017-08-29,ABC NY,My Portfolio/PAC,BR,US
    322,2017-08-30,ABC NY,My Portfolio/PBC,BR,US
    323,2017-08-31,ABC NY,My Portfolio/PCC,BR,US
    ]]&gt;&lt;/CData&gt;&lt;/Data&gt;
    </ProcessResult>
    </ProcessResponse>
    

    如果您受限于 XSLT-1.0,您可以使用 Entity Reference 作为 hack,如 in this SO answer 所述。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-19
      • 2021-01-15
      • 1970-01-01
      • 2020-07-02
      • 2017-04-24
      • 1970-01-01
      • 1970-01-01
      • 2019-11-07
      相关资源
      最近更新 更多