作为中间件,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 & Jill</who>
<where>went up < the hill.</where>
</root>
为什么 & 和 < 表示为 &和 <
如果它们不是以这种方式表示(转义),那么编写通用程序逻辑来解析 XML 或将 XML 转换回文本是很困难的(如果不是不可能的话)。W3C 已将 下面表格的字符定义为 保留为预定义实体。这些字符需要在格式正确的 XML 中进行转义。
字符 | 字符名称 | 实体引用 |
< | 小于 | < |
> | 大于 | > |
& | 和号 | & |
' | 单引号 | ' |
" | 引号 | " |
假设一个程序不按照上面规则进行转义。它产生下面的这样一条数据
<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 & Use this when every & in input is not escaped as &
inputContent = inputContent.replaceAll("&", "&");
// Use this when a few & are escaped as & and a few & are not escaped. This logic will avoid & to become &amp;
//inputContent = inputContent.replaceAll("&", "____someTEXT_____").replaceAll("&", "&").replaceAll("____someTEXT_____", "&");
outputstream.write(inputContent.getBytes());
} catch (Exception exception) {
getTrace().addDebugMessage(exception.getMessage());
throw new StreamTransformationException(exception.toString());
}
}
}