从 iXML 对象的一部分获取元素名称和值
Get element names and values from a section of an iXML object
我正在尝试从这个 XML 获取标签 Totales
及其子标签:
<Body>
<Receptor>
<RUTRecep>9655</RUTRecep>
</Receptor>
<Totales>
<MntNeto>63934</MntNeto>
<TasaIVA>19</TasaIVA>
<MntTotal>76081</MntTotal>
</Totales>
</Body>
我的代码returns只有标签的值,而不是标签名称:
Totales
639341976081
我想要名称和值,在 Totales
:
MntNeto
63934
TasaIVA
19
MntTotal
76081
这是我的代码:
DATA(lo_ixml) = cl_ixml=>create( ).
DATA(lo_stream_factory) = lo_ixml->create_stream_factory( ).
DATA(lo_doc) = lo_ixml->create_document( ).
IF lo_ixml->create_parser(
document = lo_doc
stream_factory = lo_stream_factory
istream = lo_stream_factory->create_istream_string( string =
`<Body> ` &&
` <Receptor> ` &&
` <RUTRecep>9655</RUTRecep> ` &&
` </Receptor> ` &&
` <Totales> ` &&
` <MntNeto>63934</MntNeto> ` &&
` <TasaIVA>19</TasaIVA> ` &&
` <MntTotal>76081</MntTotal> ` &&
` </Totales> ` &&
`</Body> ` )
)->parse( ) <> 0.
RETURN.
ENDIF.
DATA(lo_node_col) = lo_doc->get_elements_by_tag_name( name = 'Totales' ).
DATA(lo_iterator) = lo_node_col->create_iterator( ).
DATA(lo_node) = lo_iterator->get_next( ).
WHILE NOT lo_node IS INITIAL.
DATA(lf_name) = lo_node->get_name( ).
DATA(lf_value) = lo_node->get_value( ).
"do something for text
WRITE /: lf_name , lf_value.
lo_node = lo_iterator->get_next( ).
ENDWHILE.
原因是您使用的节点集合对应于名称为 Totales
的所有 XML 个元素,因此您的集合仅包含一个节点,迭代器将仅迭代一个节点. get_value
方法在所有深度级别连接节点及其子节点的所有文本。
相反,不要使用集合,获取名称为 Totales
的元素,在此节点上创建一个迭代器,它将迭代此节点及其子节点。
此外,节点可以是元素和文本(也可能是属性等其他类型)对于<name>value</name>
,有两个节点,一个是元素类型(名称),一个是文本类型(价值)。这对于处理 XML 流很有用,例如 <a>v1<b>v2</b>v3</a>
。因此,要仅处理像 <name>value</name>
这样的表单,您必须 select 个包含一个子节点的节点作为文本节点。
DATA(lo_elem) = CAST if_ixml_node( lo_doc->find_from_path( path = '/Body/Totales' ) ).
IF lo_elem IS BOUND.
DATA(lo_iterator) = lo_elem->create_iterator( ).
DATA(lo_node) = lo_iterator->get_next( ). " get /Body/Totales node
WHILE NOT lo_node IS INITIAL.
" Only nodes of the form `<name>value</name>`
IF lo_node->get_type( ) = lo_node->co_node_element
AND lo_node->get_children( )->get_length( ) = 1
AND lo_node->get_first_child( )->get_type( ) = lo_node->co_node_text.
DATA(lf_name) = lo_node->get_name( ).
DATA(lf_value) = lo_node->get_value( ).
"do something for text
WRITE /: lf_name , lf_value.
ENDIF.
lo_node = lo_iterator->get_next( ).
ENDWHILE.
ENDIF.
结果:
MntNeto
63934
TasaIVA
19
MntTotal
76081
您在代码中所做的就是转换。我的提示是:不要为已经用 XSLT 解决的问题编写不必要的代码。
以下是您可以在 SAP 中执行此操作的方法。转到事务 STRANS
并在那里创建以下 XSL 转换。让我们将其命名为 ZTEST
.
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:strip-space elements="*"/>
<xsl:template match="Totales">
<xsl:for-each select="child::*">
<xsl:value-of select="local-name()" /><xsl:text>
</xsl:text><xsl:value-of select="text()" /><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:template match="text() | comment()" />
</xsl:transform>
然后就用CALL TRANSFORMATION
来实现你想要的。
REPORT ZZZ.
START-OF-SELECTION.
DATA g_string TYPE string.
DATA(g_ref_stream_factory) = cl_ixml=>create( )->create_stream_factory( ).
DATA(g_ostream) = g_ref_stream_factory->create_ostream_cstring( g_string ).
DATA(g_istream) =
g_ref_stream_factory->create_istream_string(
string =
`<Body> ` &&
` <Receptor> ` &&
` <RUTRecep>9655</RUTRecep> ` &&
` </Receptor> ` &&
` <Totales> ` &&
` <MntNeto>63934</MntNeto> ` &&
` <TasaIVA>19</TasaIVA> ` &&
` <MntTotal>76081</MntTotal> ` &&
` </Totales> ` &&
`</Body> ` ).
CALL TRANSFORMATION ZTEST
SOURCE XML g_istream
RESULT XML g_ostream.
SPLIT g_string AT cl_abap_char_utilities=>cr_lf INTO TABLE DATA(g_tab_string).
LOOP AT g_tab_string ASSIGNING FIELD-SYMBOL(<string_line>).
WRITE / <string_line>.
ENDLOOP.
我正在尝试从这个 XML 获取标签 Totales
及其子标签:
<Body>
<Receptor>
<RUTRecep>9655</RUTRecep>
</Receptor>
<Totales>
<MntNeto>63934</MntNeto>
<TasaIVA>19</TasaIVA>
<MntTotal>76081</MntTotal>
</Totales>
</Body>
我的代码returns只有标签的值,而不是标签名称:
Totales
639341976081
我想要名称和值,在 Totales
:
MntNeto
63934
TasaIVA
19
MntTotal
76081
这是我的代码:
DATA(lo_ixml) = cl_ixml=>create( ).
DATA(lo_stream_factory) = lo_ixml->create_stream_factory( ).
DATA(lo_doc) = lo_ixml->create_document( ).
IF lo_ixml->create_parser(
document = lo_doc
stream_factory = lo_stream_factory
istream = lo_stream_factory->create_istream_string( string =
`<Body> ` &&
` <Receptor> ` &&
` <RUTRecep>9655</RUTRecep> ` &&
` </Receptor> ` &&
` <Totales> ` &&
` <MntNeto>63934</MntNeto> ` &&
` <TasaIVA>19</TasaIVA> ` &&
` <MntTotal>76081</MntTotal> ` &&
` </Totales> ` &&
`</Body> ` )
)->parse( ) <> 0.
RETURN.
ENDIF.
DATA(lo_node_col) = lo_doc->get_elements_by_tag_name( name = 'Totales' ).
DATA(lo_iterator) = lo_node_col->create_iterator( ).
DATA(lo_node) = lo_iterator->get_next( ).
WHILE NOT lo_node IS INITIAL.
DATA(lf_name) = lo_node->get_name( ).
DATA(lf_value) = lo_node->get_value( ).
"do something for text
WRITE /: lf_name , lf_value.
lo_node = lo_iterator->get_next( ).
ENDWHILE.
原因是您使用的节点集合对应于名称为 Totales
的所有 XML 个元素,因此您的集合仅包含一个节点,迭代器将仅迭代一个节点. get_value
方法在所有深度级别连接节点及其子节点的所有文本。
相反,不要使用集合,获取名称为 Totales
的元素,在此节点上创建一个迭代器,它将迭代此节点及其子节点。
此外,节点可以是元素和文本(也可能是属性等其他类型)对于<name>value</name>
,有两个节点,一个是元素类型(名称),一个是文本类型(价值)。这对于处理 XML 流很有用,例如 <a>v1<b>v2</b>v3</a>
。因此,要仅处理像 <name>value</name>
这样的表单,您必须 select 个包含一个子节点的节点作为文本节点。
DATA(lo_elem) = CAST if_ixml_node( lo_doc->find_from_path( path = '/Body/Totales' ) ).
IF lo_elem IS BOUND.
DATA(lo_iterator) = lo_elem->create_iterator( ).
DATA(lo_node) = lo_iterator->get_next( ). " get /Body/Totales node
WHILE NOT lo_node IS INITIAL.
" Only nodes of the form `<name>value</name>`
IF lo_node->get_type( ) = lo_node->co_node_element
AND lo_node->get_children( )->get_length( ) = 1
AND lo_node->get_first_child( )->get_type( ) = lo_node->co_node_text.
DATA(lf_name) = lo_node->get_name( ).
DATA(lf_value) = lo_node->get_value( ).
"do something for text
WRITE /: lf_name , lf_value.
ENDIF.
lo_node = lo_iterator->get_next( ).
ENDWHILE.
ENDIF.
结果:
MntNeto
63934
TasaIVA
19
MntTotal
76081
您在代码中所做的就是转换。我的提示是:不要为已经用 XSLT 解决的问题编写不必要的代码。
以下是您可以在 SAP 中执行此操作的方法。转到事务 STRANS
并在那里创建以下 XSL 转换。让我们将其命名为 ZTEST
.
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:strip-space elements="*"/>
<xsl:template match="Totales">
<xsl:for-each select="child::*">
<xsl:value-of select="local-name()" /><xsl:text>
</xsl:text><xsl:value-of select="text()" /><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:template match="text() | comment()" />
</xsl:transform>
然后就用CALL TRANSFORMATION
来实现你想要的。
REPORT ZZZ.
START-OF-SELECTION.
DATA g_string TYPE string.
DATA(g_ref_stream_factory) = cl_ixml=>create( )->create_stream_factory( ).
DATA(g_ostream) = g_ref_stream_factory->create_ostream_cstring( g_string ).
DATA(g_istream) =
g_ref_stream_factory->create_istream_string(
string =
`<Body> ` &&
` <Receptor> ` &&
` <RUTRecep>9655</RUTRecep> ` &&
` </Receptor> ` &&
` <Totales> ` &&
` <MntNeto>63934</MntNeto> ` &&
` <TasaIVA>19</TasaIVA> ` &&
` <MntTotal>76081</MntTotal> ` &&
` </Totales> ` &&
`</Body> ` ).
CALL TRANSFORMATION ZTEST
SOURCE XML g_istream
RESULT XML g_ostream.
SPLIT g_string AT cl_abap_char_utilities=>cr_lf INTO TABLE DATA(g_tab_string).
LOOP AT g_tab_string ASSIGNING FIELD-SYMBOL(<string_line>).
WRITE / <string_line>.
ENDLOOP.