使用动态命名空间对 XML 运行简单转换?

问题描述 投票:0回答:2

我从发送更改命名空间的子系统接收 XML 消息。 系统似乎会根据是否需要增加命名空间上的计数器。 我不知道如何在 SAP 中处理这个问题。

例如,它可能会向我发送以下内容:

<?xml version="1.0"?>
<topTag xmlns:ns1="xsd/namespacesForBoxes" 
        xmlns:ns2="xsd/namespacesForCartons" 
        xmlns:ns3="xsd/namespacesForPallets">

  <ns1:container>
    <ns1content/>
  </ns1:container>

  <ns2:container>
    <ns2:content/>
  </ns2:container>

  <ns3:container>
    <ns3:content/>
  </ns3:container>

</topTag>

到目前为止还不错,但如果不需要第二个元素,它会将托盘的计数器设置为 2,如下所示:

<?xml version="1.0"?>
<topTag xmlns:ns1="xsd/namespacesForBoxes" 
        xmlns:ns2="xsd/namespacesForPallets">

  <ns1:container>
    <ns1content/>
  </ns1:container>

  <ns2:container>
    <ns2:content/>
  </ns2:container>

</topTag>

当然,

<content>
标签将根据我这边的命名空间保存不同的值,因此转换将失败,因为它“硬编码”了预期的命名空间。

有没有办法通过简单的转换来实现这一点? 该结构相当大,因此通过代码动态转换是不可行的。 或者有没有办法用其他转换技术来做到这一点?

追问:这正常吗? 对我来说,这似乎是一件非常疯狂的事情,如果不需要命名空间,他们不应该切换名称。这使得将数据追溯到字符串变得非常困难。

xml xslt transform abap abap-st
2个回答
2
投票

正如 Siebe Jongebloed 已经指出的那样,XML 文档的使用者永远不应该使用命名空间前缀(如

ns1
),而应使用命名空间 URI(如
xsd/namespacesForBoxes
)。

简单转换遵循此规则并比较命名空间 URI,而不是前缀,如以下示例所示:

<?sap.transform simple?>
<tt:transform xmlns:tt="http://www.sap.com/transformation-templates"
 xmlns:ddic="http://www.sap.com/abapxml/types/dictionary"
 xmlns:ns1="namespace_uri">
 <tt:root name="ROOT" type="ddic:SCARR"/>
 <tt:template>
  <ns1:Airline>
   <tt:value ref=".ROOT.CARRID"/>
  </ns1:Airline>
 </tt:template>
</tt:transform>

当您使用这个简单的转换将 ABAP 转换为 XML 时,您将获得命名空间前缀

ns1
。但是您可以交换 XML 文档中的名称空间前缀,并且仍然使用相同的简单转换将 XML 转换回 ABAP:

data: scarr     type scarr,
      xmlstring type string.
scarr-carrid = 'XX'.
call transformation ...
 source root = scarr
 result xml xmlstring.
write / xmlstring.
replace all occurrences of 'ns1' in xmlstring with 'ns2'.
call transformation ...
 source xml xmlstring
 result root = scarr.
write / scarr-carrid.

0
投票

Heiko 之前的答案是正确的,简单的转换可以处理命名空间,我的解决方案所缺少的(除了缺乏命名空间处理之外)是条件检查。

如果您有三个名称空间,并且它们可能会更改数字,因为并非每个转换都需要所有名称空间,您需要使它们在转换中成为“可选”,如下所示:

    <tt:template>

    <top_element
        xmlns:ns1="xsd/namespacesForBoxes"
        xmlns:ns2="xsd/namespacesForCartons"
        xmlns:ns3="xsd/namespacesForPallets">
      <tt:namespace name="ns1"/>
      <tt:namespace name="ns2"/>
      <tt:namespace name="ns3"/>

        <tt:cond s-check="not-initial(ref('.telegram.BOX_ID'))">
          <ns1:container>
            <tt:attribute name="box-id" value-ref=".telegram.BOX_ID"/>
          </ns1:container>
        </tt:cond>

        <tt:cond s-check="not-initial(ref('.telegram.CARTON_ID'))">
          <ns2:container>
            <tt:attribute name="carton-id" value-ref=".telegram.CARTON_ID"/>
          </ns2:container>
        </tt:cond>

        <tt:cond s-check="not-initial(ref('.telegram.PALLET_ID'))">
          <ns3:container>
            <tt:attribute name="pallet-id" value-ref=".telegram.PALLET_ID"/>
          </ns3:container>
        </tt:cond>


    </top_element>

</tt:template>

这适用于我的测试报告:

TYPES: BEGIN OF ts_test,
         box_id    TYPE char10,
         carton_ID TYPE char10,
         pallet_ID TYPE char10,
       END OF ts_test.

DATA(lv_res1) = VALUE ts_test( ).
DATA(lv_res2) = VALUE ts_test( ).

CONCATENATE
'<top_element '
'xmlns:ns1="xsd/namespacesForBoxes" '
'xmlns:ns2="xsd/namespacesForCartons" '
'xmlns:ns3="xsd/namespacesForPallets">'
'<ns1:container box-id="BOX"/>'
'<ns2:container carton-id="CARTON"/>'
'<ns3:container pallet-id="PALLET"/>'
'</top_element>'
INTO DATA(lv_trans1)
RESPECTING BLANKS.

CONCATENATE
'<top_element '
'xmlns:ns1="xsd/namespacesForBoxes" '
'xmlns:ns2="xsd/namespacesForPallets">'
'<ns1:container box-id="BOX"/>'
'<ns2:container pallet-id="PALLET"/>'
'</top_element>'
INTO DATA(lv_trans2)
RESPECTING BLANKS.

CALL TRANSFORMATION z_namespace_test
  SOURCE XML lv_trans1
  RESULT telegram = lv_res1.

CALL TRANSFORMATION z_namespace_test
  SOURCE XML lv_trans2
  RESULT telegram = lv_res2.

感谢您的投入!

© www.soinside.com 2019 - 2024. All rights reserved.