内容


在 XMLNS 域中操作名称空间构造

Comments

引言

IBM® WebSphere® Business Integration Message Broker V5(以下称为 WebSphere Message Broker)为 XML Schema 名称空间提供了完全的支持。在网络上处理 XML 消息时,您可以使用三种方法来解析和编写 XML 消息:XML 域、XMLNS 域和 MRM 域。XML 域提供了基本的解析和编写工具来检查输入消息是否格式良好,但是却不对其进行验证。XMLNS 域提供了与 XML 域同等的功能,只不过还增加了名称空间支持。MRM 域提供了消息目录来验证消息的结构和值以及所分配的默认值。

名称空间支持提供了记录逻辑树中每一项的名称空间属性的功能。您可以使用现有 ESQL 词汇的扩展来设置和询问这些属性。MRM 域还为定义前缀和 URI 对之间的映射提供了构建时支持。这允许您指定将 XML 文档写入网络的首选方式。在许多常见的业务场景中,没有必要验证 XML 文档是否符合元数据模型。

在获得更好的性能和免于手工或通过 XML Schema 导入(或同等方式)定义目录的布局方面,XMLNS 域被认为是一种更好的做法。ESQL 为将 XMLNS 域中的输出文档建模成与 MRM 域的构建时文档具有相同的程度提供了灵活性。以下几部分首先简要介绍了 XML 和名称空间构造,接着说明了使用 ESQL 创建它们的方法。

除非另有说明,本文对“W3 一致性”的所有引用都是指可扩展标记语言(Extensible Markup Language,XML)1.0(第二版)规范。在某些地方,本文中给出的 ESQL 片段基于前面的部分的代码,所以应该按顺序将其添加到计算机节点中。新的消息是根据输出创建的,因此您可以使用任何有效的输入消息。为简单起见,建议您不取消注释标准计算节点模板中的代码行 CALL CopyMessageHeaders();,并且在其后加上本文所提供的 ESQL 代码。

创建 XML 声明

W3C 推荐标准指定所有格式良好的 XML 文档均以 XML 声明开头。该声明声明文档实现 XML 的哪一个版本。您可以使用附加属性来指定是否将文档分类为“独立 (standalone)”以及所选的代码页。

独立属性向 XML 处理器和验证器发出信号,指示 XML 文档是否需要将该文档实体之外的任何标记应用于其内容。应用于 XML 文档的标记的常见例子包括具有缺省值和 XML 实体(amp、lt、gt、apos 和 quot 除外)的属性。有关进一步的信息,请参见 W3C 推荐标准:可扩展标记语言 (XML) 1.0(第二版)站点

将文档实体看作是 XML 处理器遇到的 XML 文档的第一项。WebSphere Message Broker 将独立属性的值看作是不相关的。standalone=no 表示相关的 XML 文档依赖于外部定义的 DTD。WebSphere Message Broker 的当前版本不解析外部定义的 DTD,因此将忽略它们。更重要的是,在输出端,您可能要考虑正确地设置这个属性,因为业务中间件实现下游的 XML 处理器可能必须解释 WebSphere Messsage Broker 的编写器创建的 XML 文档。

Encoding 属性为 XML 处理器提供用于确定外部解析实体中的字符所用编码的方法。强制要求符合 W3C 规范的 XML 处理器能够解释采用 UTF-8 和 UTF-16 两种编码方式的实体。这些值经常出现在 XML 文档的 Encoding 属性中。WebSphere Message Broker 中的 ESQL 允许将 Encoding 属性设置为可以传送到 XML 处理器的备用值。与 W3C 规范兼容的编码可接受的名称只包括拉丁字符。请注意,这个编码值完全独立于 WebSphere MQ 编码,您必须在消息头中单独对其进行设置。

ESQL 代码

-- Note that the following ESQL syntax was originally devised for the 
-- XML domain and is therefore also applicable to versions of WebSphere
-- Business Integration Message Broker which pre-date Version 5.0
SET OutputRoot.XMLNS.(XML.XmlDecl).(XML.Version) = '1.0';
SET OutputRoot.XMLNS.(XML.XmlDecl).(XML.Encoding) = 'UTF-8';
SET OutputRoot.XMLNS.(XML.XmlDecl).(XML.Standalone) = 'no';

输出示例

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>

创建标准 XML 元素

XML 文档必须包含每个元素匹配的开始标记和结束标记。5.0 版扩展了用于创建 Message Broker 逻辑树中的元素(由消息流末尾的 XML 编写器进行解释)的语法。您可以使用两种常见的技术:

  • 使用 CREATE 语句来给逻辑树添加新的字段。
  • 使用 SET 语句来更改逻辑树中现有的字段或者在这些字段不存在的情况下创建它们。

当采用识别名称空间的方式时,以逻辑树的 XMLNS 域中的字段为前缀。在 ESQL SET 语句语法中,用冒号分隔限定名 (Qualified Name) 的两部分,以此来表示这一点。可以声明一个新的 NAMESPACE 常量,这隐式声明了一个字符数据类型的常量。我推荐这种做法,因为这可以防止您无意中更改名称空间,并且有助于减少键入错误。 这样的 DECLARE 语句也意味着代码更加简洁。您不需要在整个代码中多次重复键入完整的 URI。URI 和名称空间前缀的这种映射仅仅是为开发人员考虑。请注意,使用 ESQL 中的这些构造并不影响在网络上呈现消息的方式。有关如何做到这一点的详细信息,请参阅本文后面的部分 创建名称空间前缀和 URI 对映射

CREATE 语句还可以利用其新的 NAMESPACE 子句中的 NAMESPACE 变量类型。当使用 CREATE FIELD 语句时,请确保按照正确的顺序指定每个子句(TYPE、NAMESPACE、NAME 和 VALUE)。这避免了部署时错误。

ESQL 代码

DECLARE Env NAMESPACE 'www.Envelope.com';
DECLARE Body NAMESPACE 'www.Body.com';
DECLARE Child NAMESPACE 'www.Child.com';
-- The SET statement syntax is extended for namespaces ...
SET OutputRoot.XMLNS.Env:Envelope.Body:BodyOne.ChildOne = 'Child One Data';
SET OutputRoot.XMLNS.Env:Envelope.Body:BodyOne.ChildOne NAMESPACE = Child;
-- Namespaces syntax can be combined with SET statements which use 
-- Special Value Syntax to control mark-up more tightly too ...
SET OutputRoot.XMLNS.Env:Envelope.Body:BodyOne.Child:ChildTwo.(XML.Content) 
= 'Child Two Data';
-- Now switch my attention to using CREATE statements with namespace information
-- CREATE statements can be used for fields which will eventually be rendered as
-- XML Elements and XML Attributes.
-- If an XML element is required then use a TYPE clause of "Name".  Note that this
-- is different to the MRM domain due to the different methods of logical tree 
-- interpretation between domains ... 
DECLARE MovingPointer REFERENCE TO OutputRoot.XMLNS.*:Envelope.*:
BodyOne.*:ChildTwo;
CREATE NEXTSIBLING OF MovingPointer AS MovingPointer TYPE Name 
NAMESPACE Child NAME 'ChildThree' VALUE 'This will be overwritten later in 
the ESQL code';
-- With knowledge of the types which are used by the XMLNS domain,
-- it is possible to add values which will be interpreted in the 
-- intended way by the XML writer.  Normally a SET statement would
-- be used to append data to a node that already exists in the tree  ...
CREATE FIRSTCHILD OF MovingPointer TYPE 0x02000000 VALUE 'Child Three Data';		
-- So the "normal" method of SET would have been ...
SET OutputRoot.XMLNS.Env:Envelope.Body:BodyOne.Child:ChildThree VALUE = 'This 
overwrites Child Three Data so should display in the final message';
DECLARE Attr NAMESPACE 'www.Attributes.com';
-- If an XML attribute is required then use a TYPE clause of "NameValue" ...
CREATE FIRSTCHILD OF MovingPointer AS MovingPointer TYPE NameValue 
NAME 'AttributeOne' VALUE 'Attribute One Data';
-- The syntax of CREATE can also be used to place attributes in a particular namespace ...
CREATE NEXTSIBLING OF MovingPointer AS MovingPointer TYPE NameValue 
NAMESPACE Attr NAME 'AttributeTwo' VALUE 'Attribute Two Data';

如果把上面的代码添加到前面的示例中,系统将给出以下输出消息。

输出示例

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<NS1:Envelope xmlns:NS1="www.Envelope.com">
  <NS2:BodyOne xmlns:NS2="www.Body.com">
  <NS3:ChildOne xmlns:NS3="www.Child.com">Child One Data</NS3:ChildOne>
  <NS4:ChildTwo xmlns:NS4="www.Child.com">Child Two Data</NS4:ChildTwo>
  <NS5:ChildThree xmlns:NS5="www.Child.com" AttributeOne="Attribute One Data" 
  xmlns:NS6="www.Attributes.com" NS6:AttributeTwo="Attribute Two Data">
  This overwrites Child Three Data so should display in the
   final message</NS5:ChildThree>
 <NS2:BodyOne>
</NS1:Envelope>

创建名称空间前缀和 URI 对映射

符合 W3C 名称空间推荐标准的 XML 文档可以提供缩写的前缀来表示完整的 URI 名称空间。这些声明的作用在于将名称空间前缀与作为快捷方式的特定 URI 相关联,以后您就可以在 XML 消息中重用该快捷方式。当采用 XMLNS 域时,WebSphere Message Broker 不维护一个目录来描述要写入网络的消息的格式。所有在流内创建的消息都包含分类为“自定义 (Self-defining)”的字段。由于缺少消息集定义(消息集定义包含在转换到位流时应该如何呈现消息的详细信息),因此需要将数据包含在逻辑树中。由于这个缘故,为了在采用 XMLNS 域时建立前缀和 URI 映射,您需要编写 ESQL 语句来对逻辑树进行这些更改。

ESQL 代码

-- Because we are working in the XMLNS domain, it is not possible
-- to set up a list of namespace prefix / URI pairs as we would in 
-- the MRM Domain ... So instead we can specify to the XML Writer
-- specific prefixes to be used on output by ensuring that the mappings
-- between the prefix and namespaces are explicitly added in 
-- declarations made directly in the message tree:
DECLARE Chosen NAMESPACE 'www.ChosenPrefix.com';
DECLARE MovingPointer1 REFERENCE TO OutputRoot.XMLNS.*:Envelope.*:BodyOne;
CREATE FIRSTCHILD OF MovingPointer1 AS MovingPointer1 TYPE 0x07000012 
NAMESPACE 'xmlns' NAME 'ChosenPrefix' VALUE 'www.ChosenPrefix.com';
MOVE MovingPointer1 PARENT;
CREATE LASTCHILD OF MovingPointer1 AS MovingPointer1 
NAMESPACE Chosen NAME 'ChildFour' VALUE 'Child Four Data - this element does not 
have an auto-generated prefix but uses the prefix specified using ESQL ... ChosenPrefix';

如果把上面的代码添加到前面的示例中,系统将给出以下输出消息。

Sample output

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<NS1:Envelope xmlns:NS1="www.Envelope.com">
 <NS2:BodyOne xmlns:NS2="www.Body.com" xmlns:ChosenPrefix="www.ChosenPrefix.com">
  <NS3:ChildOne xmlns:NS3="www.Child.com">Child One Data</NS3:ChildOne>
  <NS4:ChildTwo xmlns:NS4="www.Child.com">Child Two Data</NS4:ChildTwo>
  <NS5:ChildThree xmlns:NS5="www.Child.com" AttributeOne="Attribute One Data" 
  xmlns:NS6="www.Attributes.com" NS6:AttributeTwo="Attribute Two Data">This 
  overwrites 
  Child Three Data so should display in the final message</NS5:ChildThree>
  <ChosenPrefix:ChildFour>Child Four Data - this element does not 
  have an auto-generated prefix
  but uses the prefix specified using ESQL ... ChosenPrefix</ChosenPrefix:ChildFour>
 </NS2:BodyOne>
</NS1:Envelope>

操作缺省名称空间声明

您可以采用 XML 语法来定义前缀和 URI 映射,以便提供所谓的“缺省 (Default)”名称空间声明。这样的声明将把一个特定的名称空间与缺省前缀相关联。这意味着不带前缀的 XML 元素驻留在没有链接前缀的 URI 所描述的名称空间中。请注意,名称空间规范为属性提供了特殊的状态。属性不受缺省名称空间声明的影响。如果您定义一个不带前缀的属性,则它没有名称空间。

通过在 WebSphere Message Broker 中使用 ESQL,您可以在逻辑树中创建字段。在消息写入网络时,WebSphere Message Broker 的 XML 编写器将把它们解释为缺省名称空间声明。

ESQL 代码

-- Now insert some default namespace declarations.  Still operating on a logical tree
-- in the XMLNS domain (not the MRM domain) ... These declarations are respected by the
-- XML writer ... i.e. when writing out elements in the default namespace, 
they are not prefixed.
DECLARE MovingPointer2 REFERENCE TO OutputRoot.XMLNS.*:Envelope.*:BodyOne;
CREATE FIRSTCHILD OF MovingPointer2 TYPE 0x07000012 NAME 'xmlns'
 VALUE 'www.BodyDefault.com';
-- Now move to the Envelope level
MOVE MovingPointer2 PARENT;
CREATE FIRSTCHILD OF MovingPointer2 TYPE 0x07000012 NAME 'xmlns' VALUE '
www.EnvelopeDefault.com';
-- This demonstrates setting different default namespaces at different levels in an XML
-- document.  Some developers consider this bad practice, but it is a common technique
 used
-- in Enveloped documents, which undergo partial parsing by subsequent XML processors,
-- particularly prevalent in SOAP implementations in the Web Services arena.
-- Having set up the default namespace declarations, we can now define elements which
-- reside in 
-- these default namespaces, and then check the output bitstream to make sure they are
 written 
-- without any namespace prefixes in front of them.
DECLARE EnvelopeDefault NAMESPACE 'www.EnvelopeDefault.com';
DECLARE BodyDefault NAMESPACE 'www.BodyDefault.com';
MOVE MovingPointer2 LASTCHILD TYPE 0x01000000 NAMESPACE *;
CREATE NEXTSIBLING OF MovingPointer2 NAMESPACE EnvelopeDefault NAME 'BodyTwo' 
VALUE 'Body Two Data - this element is unprefixed because it resides in the current 
default namespace of www.EnvelopeDefault.com';
MOVE MovingPointer2 LASTCHILD TYPE 0x01000000 NAMESPACE *;
CREATE NEXTSIBLING OF MovingPointer2 AS MovingPointer2 NAMESPACE BodyDefault 
NAME 'ChildFive' VALUE 'Child Five Data - this element is unprefixed because it 
resides in 
the current default namespace of www.BodyDefault.com';

如果把上面的代码添加到前面的示例中,系统将给出以下输出消息。

输出示例

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<NS1:Envelope xmlns:NS1="www.Envelope.com" xmlns="www.EnvelopeDefault.com">
 <NS2:BodyOne xmlns:NS2="www.Body.com" xmlns="www.BodyDefault.com" 
 xmlns:ChosenPrefix="www.ChosenPrefix.com">
  <NS3:ChildOne xmlns:NS3="www.Child.com">Child One Data</NS3:ChildOne>
  <NS4:ChildTwo xmlns:NS4="www.Child.com">Child Two Data</NS4:ChildTwo>
  <NS5:ChildThree xmlns:NS5="www.Child.com" AttributeOne="Attribute One Data" 
  xmlns:NS6="www.Attributes.com" NS6:AttributeTwo="Attribute Two Data">
  This overwrites Child Three Data so should display in the final message
  </NS5:ChildThree>
  <ChosenPrefix:ChildFour>Child Four Data - this element does not have an 
  auto-generated prefix but uses the prefix specified using ESQL ... ChosenPrefix<
  /ChosenPrefix:ChildFour>
  <ChildFive>Child Five Data - this element is unprefixed because it 
  resides in the current default 
namespace of www.BodyDefault.com</ChildFive>
 </NS2:BodyOne>
 <BodyTwo>Body Two Data - this element is unprefixed because it resides in the 
 current default
namespace of www.EnvelopeDefault.com</BodyTwo>
</NS1:Envelope>

结束语

本文提供了一种方法,使用这种方法,可以在 WebSphere Business Integration Message Broker V5 的 XMLNS 域中创建一整套 XML 名称空间构造。这种方法为在网络上创建消息提供了编写代码可能需要的一整套构造,它们可以在使用 Message Repository Manager Domain 时发挥作用。文中提供的 ESQL 代码示例演示了如何创建与通过消息集设置生成的消息等价的消息。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere, XML
ArticleID=88435
ArticleTitle=在 XMLNS 域中操作名称空间构造
publish-date=02032005