SAP简单的动态命名空间转换

huangapple go评论83阅读模式
英文:

SAP simple transformations with dynamic namespaces

问题

我从一个发送不断更改命名空间的子系统接收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> 标签会根据我这边的命名空间包含不同的值,所以这种转换会失败,因为它在预期的命名空间上“硬编码”。

在简单的转换中是否有实现这一点的方法?结构相当复杂,所以通过代码进行动态转换不可行。还有没有其他的转换技术可以做到这一点?

后续问题:这种情况正常吗?对我来说,这似乎是一个非常狂野的实现方式,如果不需要命名空间,它们就不应该更改名称。这只会使得追溯数据到字符串变得非常困难。

英文:

I receive XML messages from a subsystem that sends changing namespaces.
The system seems to increase a counter on a namespace depending on if its needed.
I don't know how to handle this in SAP.

For example it might send me this:

&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;topTag xmlns:ns1=&quot;xsd/namespacesForBoxes&quot; 
        xmlns:ns2=&quot;xsd/namespacesForCartons&quot; 
        xmlns:ns3=&quot;xsd/namespacesForPallets&quot;&gt;

  &lt;ns1:container&gt;
    &lt;ns1content/&gt;
  &lt;/ns1:container&gt;

  &lt;ns2:container&gt;
    &lt;ns2:content/&gt;
  &lt;/ns2:container&gt;

  &lt;ns3:container&gt;
    &lt;ns3:content/&gt;
  &lt;/ns3:container&gt;

&lt;/topTag&gt;

which would be fine so far, but if the second element is not needed it would set the counter for pallets to 2, like so:

&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;topTag xmlns:ns1=&quot;xsd/namespacesForBoxes&quot; 
        xmlns:ns2=&quot;xsd/namespacesForPallets&quot;&gt;

  &lt;ns1:container&gt;
    &lt;ns1content/&gt;
  &lt;/ns1:container&gt;

  &lt;ns2:container&gt;
    &lt;ns2:content/&gt;
  &lt;/ns2:container&gt;

&lt;/topTag&gt;

Of course the &lt;content&gt; tag would hold different values depending on the namespace on my side, so the transformation will fail as it "hardcodes" the expected namespace.

Is there a way to implement this in simple transformations?
The structure is quite big, so dynamic transformation via code is not feasible.
Or is there a way to do this with other transformation technices?

Followup question: Is this normal?
To me this seems like a very wild thing to implement, if namespaces are not needed they should not switch names. This just makes it horribly difficult to trace data back to the string.

答案1

得分: 2

正如Siebe Jongebloed已经指出的,XML文档的使用者不应该使用命名空间前缀(比如ns1),而应该使用命名空间的URI(比如xsd/namespacesForBoxes)。

简单的转换遵循这个规则,比较命名空间的URI,而不是前缀,就像以下示例所演示的那样:

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

当你使用这个简单的转换将ABAP转换成XML时,你会得到命名空间前缀ns1。但你可以在XML文档中更改命名空间前缀,仍然可以使用相同的简单转换将XML转换回ABAP:

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

As Siebe Jongebloed already pointed out, consumers of XML documents should never work with the namespace prefixes (like ns1) but work instead with the namespace URIs (like xsd/namespacesForBoxes).

Simple transformations follow this rule and compare the namespace URI, not the prefix, as demonstrated by the following example:

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

When you use this simple transformation to transform ABAP into XML, you get the namespace prefix ns1. But you can exchange the namespace prefix in the XML document and still use the same simple transformation to transform the XML back into ABAP:

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

答案2

得分: 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.

感谢您的输入!

英文:

The previous answer from Heiko is correct, simple transformations can handle namespaces, what my solution was lacking (in addition to lacking namespace handling) was a condition check.

If you have three namespaces and they might change the numbers because not all of them are needed in every transformation you need to make them "optional" in the transformation, like so:

    &lt;tt:template&gt;

    &lt;top_element
        xmlns:ns1=&quot;xsd/namespacesForBoxes&quot;
        xmlns:ns2=&quot;xsd/namespacesForCartons&quot;
        xmlns:ns3=&quot;xsd/namespacesForPallets&quot;&gt;
      &lt;tt:namespace name=&quot;ns1&quot;/&gt;
      &lt;tt:namespace name=&quot;ns2&quot;/&gt;
      &lt;tt:namespace name=&quot;ns3&quot;/&gt;

        &lt;tt:cond s-check=&quot;not-initial(ref(&#39;.telegram.BOX_ID&#39;))&quot;&gt;
          &lt;ns1:container&gt;
            &lt;tt:attribute name=&quot;box-id&quot; value-ref=&quot;.telegram.BOX_ID&quot;/&gt;
          &lt;/ns1:container&gt;
        &lt;/tt:cond&gt;

        &lt;tt:cond s-check=&quot;not-initial(ref(&#39;.telegram.CARTON_ID&#39;))&quot;&gt;
          &lt;ns2:container&gt;
            &lt;tt:attribute name=&quot;carton-id&quot; value-ref=&quot;.telegram.CARTON_ID&quot;/&gt;
          &lt;/ns2:container&gt;
        &lt;/tt:cond&gt;

        &lt;tt:cond s-check=&quot;not-initial(ref(&#39;.telegram.PALLET_ID&#39;))&quot;&gt;
          &lt;ns3:container&gt;
            &lt;tt:attribute name=&quot;pallet-id&quot; value-ref=&quot;.telegram.PALLET_ID&quot;/&gt;
          &lt;/ns3:container&gt;
        &lt;/tt:cond&gt;


    &lt;/top_element&gt;

&lt;/tt:template&gt;

This works with my test-report:

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
&#39;&lt;top_element &#39;
&#39;xmlns:ns1=&quot;xsd/namespacesForBoxes&quot; &#39;
&#39;xmlns:ns2=&quot;xsd/namespacesForCartons&quot; &#39;
&#39;xmlns:ns3=&quot;xsd/namespacesForPallets&quot;&gt;&#39;
&#39;&lt;ns1:container box-id=&quot;BOX&quot;/&gt;&#39;
&#39;&lt;ns2:container carton-id=&quot;CARTON&quot;/&gt;&#39;
&#39;&lt;ns3:container pallet-id=&quot;PALLET&quot;/&gt;&#39;
&#39;&lt;/top_element&gt;&#39;
INTO DATA(lv_trans1)
RESPECTING BLANKS.

CONCATENATE
&#39;&lt;top_element &#39;
&#39;xmlns:ns1=&quot;xsd/namespacesForBoxes&quot; &#39;
&#39;xmlns:ns2=&quot;xsd/namespacesForPallets&quot;&gt;&#39;
&#39;&lt;ns1:container box-id=&quot;BOX&quot;/&gt;&#39;
&#39;&lt;ns2:container pallet-id=&quot;PALLET&quot;/&gt;&#39;
&#39;&lt;/top_element&gt;&#39;
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.

Thank you for the input!

huangapple
  • 本文由 发表于 2023年8月10日 22:04:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76876486.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定