从 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.