Xml令牌类型验证解决方法 [英] Xml token type validation workaround
问题描述
BizTalk管道组件Xml验证程序允许根据其架构实现消息的正式验证。
但xs:token的验证比标准更严格(参见
http://www.xmlplease.com/normalized )。
我经常遇到外部解析器(Java,...)生成的消息,它们在源系统中有效,并被XML Validator视为无效。
注意:Microsoft可能正在做某事。
为了克服这个问题,我决定创建一个管道组件来执行数据令牌类型的预处理,以便它是。该XML验证(为例:除去多个空格)下有效。
。对于这一点,我治疗与的XmlReader和的XmlWriter XmlReaderSetting顺序消息内省和发现待处理的类型的令牌的图案元素
结果流放在ResourceTracker中。
组件可以正常处理单元消息,但是当处理批量消息(超过1000)时,我随机出现错误: XmlValidation
- 类型:System.Xml.Schema.XmlSchemaValidationException
- 执行消息:输入'http://www.ech.ch/xmlns/ eCH-0008 / 2f:countryType'不是声明。
如果我再次传递文件,它就会正确显示。
我觉得我必须将其他对象放在ResourceTracker中,但我不知道哪个。
一个想法?
这里是代码片段:
public Microsoft.BizTalk.Message.Interop。 IBaseMessage 执行(Microsoft 。.BizTalk.Component.Interop。的 IPipelineContext 跨度>电脑,Microsoft.BizTalk.Message.Interop的 IBaseMessage 跨度>
inmsg)
{
尝试
  
{
if ( String .IsNullOrEmpty(PartsName))
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
{
&NBSP;&NBSP;&NBSP;
//处理正文部分
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
IBaseMessagePart part = inmsg.BodyPart;
;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
ProcessPartTokenDataType(part,pc,inmsg);
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; &NBSP;&NBSP;&NBSP;
}
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
else
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
{
&NBSP;&NBSP;&NBSP;
//处理显式部分
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
string [] parts = PartsName.Split( ';');
<跨度郎= "EN-US" 风格= "font-family:索拉;字体大小:9.5pt"> <跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP ;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
for ( int i = 0; i< parts.Length; i ++)
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
{
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
ProcessPartTokenDataType(inmsg.GetPart(parts [i]),pc,inmsg);
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
}
}
return inmsg;
}
catch (例外 ex)
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
{
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
throw new
SitelException 跨度>(的字符串跨度> .Format(的" ERREUR德TRAITEMENT杜管道CheckTokenTypeComponent:{0 }" ,ex.GetType()。ToString()+
" - " + ex.Message +
" - " + ex.StackTrace));
&NBSP;
}
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
}
&NBSP;&NBSP;&NBSP;&NBSP;
private void ProcessPartTokenDataType( IBaseMessagePart 部分,
IPipelineContext pc,
IBaseMessage inmsg)
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
{
if (part!= null && part.Data! =
null )
&NBSP;
{
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
Stream processedStream = ProcessTokenDataType(part.Data,pc,inmsg);
< p style ="line-height:normal; margin-bottom:0pt"> &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
processedStream.Seek(0, SeekOrigin .Begin);
;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
pc.ResourceTracker.AddResource(processedStream);
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; &NBSP;&NBSP;&NBSP;
part.Data = processedStream;
}
}
&NBSP;&NBSP;&NBSP;&NBSP;
private Stream ProcessTokenDataType(流跨度>的inputStream,
的 IPipelineContext 跨度>件,的
IBaseMessage 跨度> inmsg)
{
MemoryStream processedStream =
new MemoryStream ();
  ;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
//设置XML验证阅读器
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
XmlReaderSettings settings =
new XmlReaderSettings ();
settings.ValidationType = ValidationType .Schema;
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
跨度> settings.ValidationEventHandler + = <跨度风格= "颜色:蓝">新跨度>
的的ValidationEventHandler 跨度>(settings_ValidationEventHandler );
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
跨度>的 XmlSchemaSet中跨度>的XmlSchemaSet = GetXmlSchemaSet(PC,inmsg); 跨度>
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
settings.Schemas.Add(xmlSchemaSet);
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
使用( XmlReader reader =
XmlReader .Create(inputStream,settings))
;
{
使用( XmlWriter writer =
XmlWriter .Create(processedStream))
  ;&NBSP;&NBSP;&NBSP;
{
&NBSP;&NBSP;&NBSP;
while (reader.Read())
;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
{
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
ProcessXmlNode(读者,作家);
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
}
}
}
返回 processedStream;
}
&NBSP;&NBSP;&NBSP;&NBSP;
void settings_ValidationEventHandler( object sender,
ValidationEventArgs e)
{
//什么都不做
}
&NBSP;&NBSP;&NBSP;&NBSP;
private XmlTypeCode currentType =
XmlTypeCode 。无;
  ;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
private void ProcessXmlNode( XmlReader 阅读器,
XmlWriter 编写者)
;&NBSP;
{
开关(reader.NodeType)
;&NBSP;&NBSP;&NBSP;&NBSP;
{
case XmlNodeType .Element:
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
currentType = reader.SchemaInfo!=
null ? reader.SchemaInfo.SchemaType.TypeCode:的
XmlTypeCode 跨度> .None; 跨度>
;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
writer.WriteStartElement(reader.Prefix,reader.LocalName, reader.NamespaceURI);
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; &NBSP;
writer.WriteAttributes(reader,
true );
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP ;&NBSP;&NBSP;
if (reader.IsEmptyElement)
;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
{
currentType =
< span style ="color:#2b91af"> XmlTypeCode .None;
  ;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
writer.WriteEndElement();
< p style ="line-height:normal; margin-bottom:0pt"> ;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
}
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
break ;
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
case XmlNodeType .Text:
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
writer.WriteString(currentType == System.Xml.Schema。 XmlTypeCode .Token?
CheckTokenType(reader.Value):reader.Value);
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
currentType = System.Xml.Schema。 XmlTypeCode .None;
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
break ;
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
case XmlNodeType .Whitespace:
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP ;&NBSP;&NBSP;&NBSP;
case XmlNodeType .SignificantWhitespace:
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
writer.WriteWhitespace(reader.Value);
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
break ;
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
case XmlNodeType .CDATA:
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
writer.WriteCData(reader.Value);
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
break ;
;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
case XmlNodeType .EntityReference:
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
writer.WriteEntityRef(reader.Name);
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
break ;
<跨度>&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;
case XmlNodeType .XmlDeclaration:
  ;
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.DocumentType:
writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value);
break;
case XmlNodeType.Comment:
writer.WriteComment(reader.Value);
break;
case XmlNodeType.EndElement:
currentType = XmlTypeCode.None;
writer.WriteFullEndElement();
break;
}
}
private static
string CheckTokenType(string value)
{
return String.IsNullOrEmpty(value) ? value : CheckMultipleSpace(value.Trim());
}
private static
string CheckMultipleSpace(string value)
{
bool predIsSpace =
false;
String result =
String.Empty;
for (int i = 0; i < value.Length; i++)
{
if (value[i] !=
’ ’ || !predIsSpace)
result += value[i];
predIsSpace = value[i] == ’ ’;
}
return result;
}
private XmlSchemaSet GetXmlSchemaSet(IPipelineContext pc,
IBaseMessage inmsg)
{
XmlSchemaSet xmlSchemaSet =
new XmlSchemaSet();
string messageType = inmsg.Context.Read(MessageTypeProperty.Name.Name, MessageTypeProperty.Name.Namespace)
as string;
IDocumentSpec documentSpec = pc.GetDocumentSpecByType(messageType);
foreach (XmlSchema schema
in documentSpec.GetSchemaCollection())
{
xmlSchemaSet.Add(schema);
}
return xmlSchemaSet;
}
If the pipeline component wants the lifetime of the objects to last until the end of
pipeline execution, then you must add such objects to the resource tracker that your pipeline may fetch from the pipeline context.
Then why do you need this pc.ResourceTracker.AddResource(processedStream); &NBSP; functionality ?
can you try with bulk records by commenting
the above line .
The BizTalk Pipeline Component Xml Validator allows realizing formal validation of messages against their schema.
But validation of xs: token is stricter than the standard (see
http://www.xmlplease.com/normalized).
I am frequently confronted with messages generated by external parser (Java, …), which are valid in the source systems and considered invalid by the XML Validator.
NOTE: Microsoft might be doing something.
To overcome this problem, I decided to create a pipeline component that performs a pre-process of data token type so that it is valid under the XML Validator (exemple: removing multiple spaces).
For this, I treat the message with XmlReader and XmlWriter XmlReaderSetting order to introspect and discover patterns elements of type token to be treated.
The result stream is placed in the ResourceTracker.
The component work fine with unit messages, but when the treatment of batches of messages (over 1000) I randomly have errors: XmlValidation
- Type : System.Xml.Schema.XmlSchemaValidationException
- Exemple de message : Type 'http://www.ech.ch/xmlns/eCH-0008/2f:countryType' is not declared.
If I pass again the file, it goes correctly.
I feel that I must place other object in the ResourceTracker but I do not know which.
An idea?
Here the code snippet :
public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
{
try
{
if (String.IsNullOrEmpty(PartsName))
{
// Process Body part
IBaseMessagePart part = inmsg.BodyPart;
ProcessPartTokenDataType(part, pc, inmsg);
}
else
{
// Process Explicit parts
string[] parts = PartsName.Split(';');
for (int i = 0; i < parts.Length; i++)
{
ProcessPartTokenDataType(inmsg.GetPart(parts[i]), pc, inmsg);
}
}
return inmsg;
}
catch (Exception ex)
{
throw new SitelException(String.Format("Erreur de traitement du pipeline CheckTokenTypeComponent : {0}", ex.GetType().ToString() + "-" + ex.Message + "-" +ex.StackTrace));
}
}
private void ProcessPartTokenDataType(IBaseMessagePart part, IPipelineContext pc, IBaseMessage inmsg)
{
if (part != null && part.Data != null)
{
Stream processedStream = ProcessTokenDataType(part.Data, pc, inmsg);
processedStream.Seek(0, SeekOrigin.Begin);
pc.ResourceTracker.AddResource(processedStream);
part.Data = processedStream;
}
}
private Stream ProcessTokenDataType(Stream inputStream, IPipelineContext pc, IBaseMessage inmsg)
{
MemoryStream processedStream = new MemoryStream();
// Set up XML validating reader
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);
XmlSchemaSet xmlSchemaSet = GetXmlSchemaSet(pc, inmsg);
settings.Schemas.Add(xmlSchemaSet);
using (XmlReader reader = XmlReader.Create(inputStream, settings))
{
using (XmlWriter writer = XmlWriter.Create(processedStream))
{
while (reader.Read())
{
ProcessXmlNode(reader, writer);
}
}
}
return processedStream;
}
void settings_ValidationEventHandler(object sender, ValidationEventArgs e)
{
// Do nothing
}
private XmlTypeCode currentType = XmlTypeCode.None;
private void ProcessXmlNode(XmlReader reader, XmlWriter writer)
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
currentType = reader.SchemaInfo != null ? reader.SchemaInfo.SchemaType.TypeCode : XmlTypeCode.None;
writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
writer.WriteAttributes(reader, true);
if (reader.IsEmptyElement)
{
currentType = XmlTypeCode.None;
writer.WriteEndElement();
}
break;
case XmlNodeType.Text:
writer.WriteString(currentType == System.Xml.Schema.XmlTypeCode.Token ? CheckTokenType(reader.Value) : reader.Value);
currentType = System.Xml.Schema.XmlTypeCode.None;
break;
case XmlNodeType.Whitespace:
case XmlNodeType.SignificantWhitespace:
writer.WriteWhitespace(reader.Value);
break;
case XmlNodeType.CDATA:
writer.WriteCData(reader.Value);
break;
case XmlNodeType.EntityReference:
writer.WriteEntityRef(reader.Name);
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.DocumentType:
writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value);
break;
case XmlNodeType.Comment:
writer.WriteComment(reader.Value);
break;
case XmlNodeType.EndElement:
currentType = XmlTypeCode.None;
writer.WriteFullEndElement();
break;
}
}
private static string CheckTokenType(string value)
{
return String.IsNullOrEmpty(value) ? value : CheckMultipleSpace(value.Trim());
}
private static string CheckMultipleSpace(string value)
{
bool predIsSpace = false;
String result = String.Empty;
for (int i = 0; i < value.Length; i++)
{
if (value[i] != ' ' || !predIsSpace)
result += value[i];
predIsSpace = value[i] == ' ';
}
return result;
}
private XmlSchemaSet GetXmlSchemaSet(IPipelineContext pc, IBaseMessage inmsg)
{
XmlSchemaSet xmlSchemaSet = new XmlSchemaSet();
string messageType = inmsg.Context.Read(MessageTypeProperty.Name.Name, MessageTypeProperty.Name.Namespace) as string;
IDocumentSpec documentSpec = pc.GetDocumentSpecByType(messageType);
foreach (XmlSchema schema in documentSpec.GetSchemaCollection())
{
xmlSchemaSet.Add(schema);
}
return xmlSchemaSet;
}
If the pipeline component wants the lifetime of the objects to last until the end of pipeline execution, then you must add such objects to the resource tracker that your pipeline may fetch from the pipeline context.
Then why do you need this pc.ResourceTracker.AddResource(processedStream); functionality ?
can you try with bulk records by commenting the above line .
这篇关于Xml令牌类型验证解决方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!