从iXML对象的一部分获取元素名称和值

时间:2019-03-18 22:13:24

标签: xml sap abap

我正在尝试从此XML中获取标签Totales及其子元素:

<Body>
  <Receptor>
    <RUTRecep>9655</RUTRecep>
  </Receptor>
  <Totales>
    <MntNeto>63934</MntNeto>
    <TasaIVA>19</TasaIVA>
    <MntTotal>76081</MntTotal>
  </Totales>
</Body>

我的代码仅返回标签的值,而不是标签名称:

  

故事

     

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.

2 个答案:

答案 0 :(得分:2)

原因是您使用的节点集合与名称为Totales的所有XML元素相对应,因此您的集合仅包含一个节点,并且迭代器将仅迭代一个节点。方法get_value在所有深度级别上串联节点及其子节点的所有文本。

相反,不要使用集合,获取名称为Totales的元素,在此节点上创建一个迭代器,该迭代器将在此节点及其子节点上进行迭代。

此外,节点既可以是元素,也可以是文本(可能还可以是其他类型,例如属性等)。对于<name>value</name>,有两个节点,一个是元素类型(名称),一个是文本类型(值) 。这对于处理诸如<a>v1<b>v2</b>v3</a>之类的XML流很有用。因此,要仅处理<name>value</name>之类的表格,就必须选择仅包含一个子节点的节点,即文本节点。

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

答案 1 :(得分:1)

您在代码中所做的就是转换。我的提示是:不要为已经使用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.