SAP PI / PO 中的字符编码

   作为中间件,SAP PI / PO 集成了 SAP / 非 SAP 系统,这些系统使用不同的格式(文本(XML、CSV...)、二进制)来表示数据。有时,它们甚至以不同的格式对文本进行编码或使用不同的代码页。本文档有助于理解和处理这些情况。

  Code-page(内码表) 是一个表格,为每个字符分配一个编号。示例:'A' 是 65,'a' 是 97,'b' 是 98,依此类推。

“A”表示 65 岁。65 = 10 0001 (64*1 32*0 16*0 8*0 4*0 2*0 1*1)。用 0 和 1 表示代码页号就是编码

10 0001 是 65。在代码页中查找 65,它是 'A'。查找代码页号就是解码。

某些编码是固定长度的。示例 ASCII、ISO 8859-1、cp1252、UTF-32 和 ISO 8859-1 和 cp1252 必须使用 1 个字节来表示代码页号。ASCII 必须使用 1 个字节(它实际上只使用 7 个位,第 1 位被忽略)。UTF-32 必须使用 4 个字节。

某些编码是可变长度的。示例 UTF-8 和 UTF-16。UTF-8 将从 1 个字节开始,如果代码页号太大而无法用 1 个字节表示,则可以使用 2 个、3 个或 4 个字节。UTF-16 将从 2 个字节开始,如果需要,它将使用 4 个字节(即 2 个字节或 4 个字节)。

UTF-8: - UTF-8 是 Internet 上的首选编码。HTML、XML、JSON ...默认以 UTF-8 编码。

了解 UTF-8、BOM、字节序。供参考..字符、符号和 Unicode 奇迹 - 电脑爱好者 - YouTube, 计算机中的字符 - Unicode 教程 UTF-8 - YouTube

    字节顺序标记 (BOM):- 这是对目标系统有关编码的提醒。某些 Microsoft Windows 应用程序需要 BOM 才能正确解码 UTF 文本。这就是 BOM 的工作原理。如果我们发送 UTF-8 编码的文本,则我们会在该文本流前面加上 EF BB BF(十六进制)的二进制形式。然后,目标系统读取这些字符并理解“此文本流以 EF BB BF 开头,则此文本必须是 UTF-8,并且我应该使用 UTF-8 解码逻辑”。它不会显示 EF BB BF。如果我们发送 UTF-16 Big-Endian,那么我们将在该文本流前面加上 FE FF(十六进制)。然后,目标系统读取这些字符并理解“此文本流以 FE FF 开头,则此文本必须是 UTF-16 BE”。

如果目标程序不理解 BOM 提醒通知,即当它在文本流开始时看到 EF BB BF(十六进制)并且没有被编程来理解它时。它可能会将其解释为 cp1252 字符 。如果您看到任何错误或显示以  或 þÿ 或 ÿþ 开头。这意味着,目标程序没有正确解码数据。

测试源、PI/PO 和目标系统是否使用正确的编码。您可以请求源系统在其中一个数据元素中发送欧元签名 €。如果目标系统未正确解码 €,则代码页/编码存在问题。

为什么欧元符号 € 显示为 â'¬?

€ -> U+20AC (hex) -> 0010 0000 1010 1100 -> 11100010 10000010 10101100 -> E2 82 AC -> - -

请浏览 如何在 Process Integration 中使用字符编码

以下是上述文档中需要注意的一些要点。

读取 XML 时,SAP 建议将 “File Type” 设置为 “Binary”。由于 XML prolog 具有编码详细信息 <?xml version=“1.0” encoding=“utf-8”?>.SAP Note 821267。

您可以使用以下适配器模块来更改编码。

MessageTransformationBean:Transfer.ContentType = text/xml;charset=“cp1252”

TextCodepageConvertionBean:Conversion.charset = “utf-8”

XMLAnonymizerBean:anonymizer.encoding = “utf-8”

供参考。cp1252 是 ASCII 和 ISO 8859-1 的超集。UTF-8 是 cp1252 的超集,但使用的字节数可能会有所不同。

让我们处理 How to Work with Character Encodings in Process Integration 中提到的第 5 节和第 6 节中提到的问题。

1) Java mapping to change code-page/encoding. Supported Encodings.

package com.map;
import com.sap.aii.mapping.api.*;
import java.io.*;
public class ChangeEncoding_JavaMapping extends AbstractTransformation {
    @Override
    public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput) throws StreamTransformationException {
        try {
            InputStream inputStream = transformationInput.getInputPayload().getInputStream();
            OutputStream outputStream = transformationOutput.getOutputPayload().getOutputStream();
            //Read input as cp1252 and write output as UTF-8.
            byte[] b = new byte[inputStream.available()];
            inputStream.read(b);
            String inS = new String(b, "Cp1252");
            outputStream.write(inS.getBytes("UTF-8"));
        } catch (Exception ex) {
            getTrace().addDebugMessage(ex.getMessage());
            throw new StreamTransformationException(ex.toString());
        }
    }
}

结果:-

2) 用于处理 Quoted-Printable 输入的 Java 映射。

package com.map;
import com.sap.aii.mapping.api.*;
import java.io.*;
public class QuotedPrintable_JavaMapping extends AbstractTransformation {
    @Override
    public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput) throws StreamTransformationException {
        try {
            InputStream inputStream = transformationInput.getInputPayload().getInputStream();
            OutputStream outputStream = transformationOutput.getOutputPayload().getOutputStream();
            //Convert quoted-printable to unicode output. Add JAX-WS library when compiling.
            inputStream = javax.mail.internet.MimeUtility.decode(inputStream, "quoted-printable");
            //Copy Input content to Output content.
            byte[] b = new byte[inputStream.available()];
            inputStream.read(b);
            outputStream.write(b);
        } catch (Exception ex) {
            getTrace().addDebugMessage(ex.getMessage());
            throw new StreamTransformationException(ex.toString());
        }
    }
}

结果-

3) 用于处理 Base64 输入的 Java 映射。        

package com.map;
import com.sap.aii.mapping.api.*;
import java.io.*;
public class Base64_JavaMapping extends AbstractTransformation {
    @Override
    public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput) throws StreamTransformationException {
        try {
            InputStream inputStream = transformationInput.getInputPayload().getInputStream();
            OutputStream outputStream = transformationOutput.getOutputPayload().getOutputStream();
            //Decode Base64 Input content to Output content. FYI. Java 8 has java.util.Base64.
            byte[] b = new sun.misc.BASE64Decoder().decodeBuffer(inputStream);
          //Above class is internal class. As an alternative you can use below line, whichever works for you.
          //byte[] b = javax.xml.blind.DatatypeConverter().decodeBuffer(inputStream);  
          outputStream.write(b);
        } catch (Exception ex) {
            getTrace().addDebugMessage(ex.getMessage());
            throw new StreamTransformationException(ex.toString());
        }
    }
}

结果:-

4) 用于添加 BOM 的 Java 映射。

package com.map;
import com.sap.aii.mapping.api.*;
import java.io.*;
public class BOM_JavaMapping extends AbstractTransformation {
    @Override
    public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput) throws StreamTransformationException {
        try {
            InputStream inputStream = transformationInput.getInputPayload().getInputStream();
            OutputStream outputStream = transformationOutput.getOutputPayload().getOutputStream();
            //Copy Input content to Output content.
            byte[] b = new byte[inputStream.available()];
            inputStream.read(b);
            //Prefix BOM. For UTF-8 use "0xEF,0xBB,0xBF". For UTF-16BE use "0xFE,0xFF". For UTF-16LE use "0xFF,0xFE".
            outputStream.write(0xEF);  outputStream.write(0xBB);  outputStream.write(0xBF);
            outputStream.write(b);
        } catch (Exception ex) {
            getTrace().addDebugMessage(ex.getMessage());
            throw new StreamTransformationException(ex.toString());
        }
    }
}

结果: - BOM 字符将不会显示。

5) 用于处理 XML 转义序列的 Java 映射。

例子数据 

Jack & Jill went up < the hill.

符合 W3C 标准的程序将生成以下 XML。

<root>
  <who>Jack &amp; Jill</who>
  <where>went up &lt; the hill.</where>
</root>

为什么 & 和 < 表示为 &amp;和 &lt;

如果它们不是以这种方式表示(转义),那么编写通用程序逻辑来解析 XML 或将 XML 转换回文本是很困难的(如果不是不可能的话)。W3C 已将 下面表格的字符定义为 保留为预定义实体。这些字符需要在格式正确的 XML 中进行转义。

字符字符名称实体引用
<小于&lt;
>大于&gt;
&和号&amp;
'单引号&apos;    
"引号&quot;

假设一个程序不按照上面规则进行转义。它产生下面的这样一条数据

<root>
  <who>Jack & Jill</who>
  <where>went up < the hill.</where>
</root>

这不是格式正确的 XML。它将在消息映射中失败,并显示错误“字符引用”&xxxxx“是无效的 XML 字符”。SCN 上的常见问题,“在消息映射中处理 XML 中的特殊字符”。图形消息映射、XSLT、DOM、SAX 无法处理此 XML。

这不是格式正确的 XML。它将在消息映射中失败,并显示错误“字符引用”&xxxxx“是无效的 XML 字符”。SCN 上的常见问题,“在消息映射中处理 XML 中的特殊字符”。图形消息映射、XSLT、DOM、SAX 无法处理此 XML。

强烈建议请求发件人系统,以修复代码并生成格式正确的 XML。

在大多数情况下,& 不会被转义。如果 < 未转义,则 handle 是非常默认的。Java 映射可用于生成格式正确的 XML。注意:通用程序逻辑很困难,因为&是预定义实体。根据需要定制以下解决方案。

在PI的message mapping之前中实现下面的 Java mapping:

package com.javaMapping;
import java.io.*;
import com.sap.aii.mapping.api.*;
public class WellformedXML_JavaMapping extends AbstractTransformation {
    @Override
    public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput) throws StreamTransformationException {
        try {
            InputStream inputstream = transformationInput.getInputPayload().getInputStream();
            OutputStream outputstream = transformationOutput.getOutputPayload().getOutputStream();
            // a) Copy Input content to String
            byte[] b = new byte[inputstream.available()];
            inputstream.read(b);
            String inputContent = new String(b);
            // b) Replace all & with &amp; Use this when every & in input is not escaped as &amp;
            inputContent = inputContent.replaceAll("&", "&amp;");
            // Use this when a few & are escaped as &amp; and a few & are not escaped. This logic will avoid &amp; to become &amp;amp;
            //inputContent = inputContent.replaceAll("&amp;", "____someTEXT_____").replaceAll("&", "&amp;").replaceAll("____someTEXT_____", "&amp;");
        
            outputstream.write(inputContent.getBytes());
        } catch (Exception exception) {
            getTrace().addDebugMessage(exception.getMessage());
            throw new StreamTransformationException(exception.toString());
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值