Kader Yildirim
A la découverte de BizTalk Server 2006 1/3
Développer un désassembleur pour BizTalk Server 2006 R2
Par Kader Yildirim publié le 02/03/2008 à 21:58, lu 5021 fois, 6 pages
 3 | Extraction des sous-documents
La première étape consiste à développer une fonction qui prend en paramètre un document XML et une liste de XSD et qui retourne une liste de documents XML compatibles avec au moins l'un des XSD. La fonction peut être schématisée comme suit :
 
/content/af013d85-430c-482b-8450-a88c26dc0881/ExtractDocument.png
 
Pour BizTalk un schéma est caractérisé par son namespace et le nom du noeud racine.
Si le namespace et le nom d'un noeud du document XML donné en entrée correspondent avec ceux d'un schéma alors on peut supposer que ce noeud est potentiellement valide et l'extraire. C'est ce que fait le code ci-dessous :

public Dictionary<Guid, Pair<Schema, Stream>> Find(Stream doc, SchemaList schemas)

        {

            Pair<string, string> root = null;

            Dictionary<Guid, Pair<Schema, Stream>> parts = new Dictionary<Guid, Pair<Schema, Stream>>();

 

            using (XmlReader docReader = XmlReader.Create(doc))

            {

                MemoryStream newDocStream = new MemoryStream();

                using (XmlWriter newDocWriter = XmlWriter.Create(newDocStream))

                {

                    while (docReader.Read())

                    {

                        if (docReader.NodeType == XmlNodeType.Element)

                        {

                            Pair<string, string> p = new Pair<string, string>(docReader.LocalName, docReader.NamespaceURI);

 

                            if (root == null)

                                root = p;

 

                            Schema schema = GetAssociatedSchema(schemas, p);

                            if (null != schema)

                            {

                                if (p.Left == root.Left && p.Right == root.Right)

                                {

                                    foreach (Pair<Schema, Stream> pair in parts.Values)

                                        pair.Right.Close();

                                    parts.Clear();

                                    newDocStream.Close();

                                    parts.Add(Guid.Empty, new Pair<Schema, Stream>(schema, doc));

                                    doc.Position = 0;

                                    return parts;

                                }

 

                                MemoryStream part = new MemoryStream();

                                using (XmlWriter partWriter = XmlWriter.Create(part))

                                {

                                    PipelineUtils.Util.WriteShallowNode(docReader, partWriter);

                                    while (docReader.Read())

                                    {

                                        PipelineUtils.Util.WriteShallowNode(docReader, partWriter);

                                        if (p.Left == docReader.LocalName &&

                                            p.Right == docReader.NamespaceURI &&

                                            docReader.NodeType == XmlNodeType.EndElement)

                                        {

                                            break;

                                        }

                                    }

                                }

 

                                Guid g = Guid.NewGuid();

                                parts.Add(g, new Pair<Schema, Stream>(schema, part));

                                part.Position = 0;

                                newDocWriter.WriteElementString(r_TagName, g.ToString());

                                continue;

                            }

                        }

 

                        PipelineUtils.Util.WriteShallowNode(docReader, newDocWriter);

                    }

                }

                parts.Add(Guid.Empty, new Pair<Schema, Stream>(null, newDocStream));

                newDocStream.Position = 0;

            }

 

            return parts;

        }

La fonction WriteShallowNode permet de copier le contenu d'un reader vers un writer.

Toutefois si l'utilisateur le souhaite il peut forcer la validation complète des fragments ainsi extraits. Dans ce cas le code suivant réinjecte dans la source les documents non valides :

public void ValidateXmlDocumentsAgainstSchema(Dictionary<Guid, Pair<Schema, Stream>> dvn,

            Dictionary<Schema, XmlSchemaCollection> s)

        {

            if (null == dvn)

                throw new ArgumentNullException();

 

            if (1 == dvn.Count)

                return;

 

            Pair<Schema, Stream> body = dvn[Guid.Empty];

            body.Right.Position = 0;

            MemoryStream stream = new MemoryStream();

            using (XmlReader reader = XmlReader.Create(body.Right))

            {

                using (XmlWriter writer = XmlWriter.Create(stream))

                {

                    while (reader.Read())

                    {

                        if (reader.NodeType == XmlNodeType.Element &&

                            reader.LocalName == r_TagName)

                        {

                            reader.Read();

                            Guid g = new Guid(reader.Value);

                            using (XmlReader partReader = Validate(dvn[g].Right, s[dvn[g].Left]))

                            {

                                reader.Read();//read guid end tag

 

                                if (null == partReader)

                                {

                                    writer.WriteElementString(r_TagName, g.ToString());

                                }

                                else

                                {

                                    do

                                    {

                                        PipelineUtils.Util.WriteShallowNode(partReader, writer);

                                    }

                                    while (partReader.Read());

 

                                    dvn[g].Right.Close();

                                    dvn.Remove(g);

                                }

                            }

                        }

                        else PipelineUtils.Util.WriteShallowNode(reader, writer);

                    }

                }

            }

            body.Right.Close();

            body.Right = stream;

            stream.Position = 0;

        }

La validation en elle-même est assez classique :

private XmlReader Validate(Stream doc, XmlSchemaCollection xsc)

        {

            if (null == doc || null == xsc)

                return null;

 

            XmlReaderSettings xrs = new XmlReaderSettings();

            xrs.ValidationType = ValidationType.Schema;

 

            foreach (XmlSchema xs in xsc)

                xrs.Schemas.Add(xs);

 

            doc.Position = 0;

            using (XmlReader reader = XmlReader.Create(doc, xrs))

            {

                try

                {

                    while (reader.Read()) ;

                }

                catch (XmlSchemaValidationException)

                {

                    doc.Position = 0;

                    XmlReader r = XmlReader.Create(doc);

                    r.MoveToContent();

                    return r;

                }

            }

            doc.Position = 0;

            return null;

 

        }

 
» Démarrer une discussion