/// <summary>
        /// Ejecuta patrones los extracción de textos
        /// almacenados.
        /// </summary>
        /// <param name="pdf"></param>
        /// <returns></returns>
        public PdfTagExtractionResult Extract(PdfUnstructuredDoc pdf)
        {
            PdfTagExtractionResult result = new PdfTagExtractionResult()
            {
                Pdf          = pdf,
                MetadataType = Type.GetType(MetadataName)
            };

            _Converters = new Dictionary <Type, object>();

            IHierarchySet hierarchySet = GetHierarchySet();

            foreach (var page in pdf.PdfUnstructuredPages)
            {
                ExtractFromRectangles(page.WordGroups,
                                      result.MetadataType, hierarchySet, result);

                ExtractFromRectangles(page.Lines,
                                      result.MetadataType, hierarchySet, result, "LinesInfos");

                ExtractFromText(result.MetadataType, result, page, hierarchySet);

                ExtractFromTextStrings(page.TextStringGroups,
                                       result.MetadataType, hierarchySet, result);
            }

            result.Converters = _Converters;

            result.GetMetadata();

            return(result);
        }
 /// <summary>
 /// Construye una nueva instancia de PdfCompareResult.
 /// </summary>
 /// <param name="pdf">PdfUnstructuredDoc a partir del cual se ha obtenido.</param>
 /// <param name="metadata">IMetadata a partir del cual se ha obtenido.</param>
 /// <param name="hierarchySet">Catálogo de jerarquías por tipo.</param>
 public PdfCompareResult(PdfUnstructuredDoc pdf, IMetadata metadata,
                         IHierarchySet hierarchySet) : this()
 {
     _Pdf          = pdf;
     _Metadata     = metadata;
     _HierarchySet = hierarchySet;
 }
        /// <summary>
        /// Ejecuta el proceso de extracción de metadatos
        /// a partir de los patrones almacenados.
        /// En este caso los metadatos deben coincidir en 4 propiedades:
        /// FontType, FontSize, ColorFill, ColorStroke.
        /// En caso de acierto, se compara la RegEx.
        /// </summary>
        /// <param name="pdfDocTextStrings">Los textStrings obtenidos con el texto y las 4 propiedades.</param>
        /// <param name="metadataType">Implementa IMetadata. Sirve para averiguar el tipo de dato. Ejemplos: int, string, etc.</param>
        /// <param name="hierarchySet">Catálogo de jerarquías.</param>
        /// <param name="result">Guarda los resultados obtenidos con este método de extracción.</param>
        private void ExtractFromTextStrings(List <PdfClownTextString> pdfDocTextStrings,
                                            Type metadataType, IHierarchySet hierarchySet, PdfTagExtractionResult result)
        {
            foreach (var textString in pdfDocTextStrings)
            {
                foreach (var pattern in PdfPatterns)
                {
                    if (pattern.SourceTypeName == "TextStringInfos")
                    {
                        if (textString.ColorFill.BaseDataObject.ToString().Equals(pattern.ColorFill) &&
                            textString.ColorStroke.BaseDataObject.ToString().Equals(pattern.ColorStroke) &&
                            textString.FontSize.ToString().Equals(pattern.FontSize) &&
                            textString.FontType.Name.Equals(pattern.FontType) &&
                            textString.Type.Equals(pattern.TsType))
                        {
                            if (pattern.TsType.Equals("NA") ||
                                (pattern.TsType.Equals("X") && textString.Rectangle != null && pattern.TsCoordinate.Equals(textString.Rectangle.Value.X.ToString())) ||
                                (pattern.TsType.Equals("Y") && textString.Rectangle != null && pattern.TsCoordinate.Equals(textString.Rectangle.Value.Y.ToString())))
                            {
                                // Cumple los 4 parámetros del textString
                                // por lo que debemos comprobar el contenido
                                // (convirtiendo el dato primero a un tipo comparable)

                                string               textInput       = textString.Text;
                                PropertyInfo         pInf            = metadataType.GetProperty(pattern.MetadataItemName);
                                ITextParserHierarchy parserHierarchy = hierarchySet.GetParserHierarchy(pInf);

                                if (pInf.PropertyType == typeof(string))
                                {
                                    parserHierarchy.SetParserRegexPattern(0, pattern.RegexPattern);
                                }

                                dynamic converter = parserHierarchy.GetConverter(pattern.RegexPattern);

                                MatchCollection matches = Regex.Matches(textString.Text, pattern.RegexPattern);

                                string val = (pattern.Position < matches.Count) ?
                                             matches[pattern.Position].Value : null;

                                object pValue = null;

                                if (val != null && converter != null)
                                {
                                    pValue = converter.Convert(val);
                                }

                                if (pValue != null && !PdfCompare.IsZeroNumeric(pValue))
                                {
                                    result.AddResult(pattern, pValue);
                                    if (!_Converters.ContainsKey(pInf.PropertyType))
                                    {
                                        _Converters.Add(pInf.PropertyType, converter);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Extrae el texto con los patrones aprendidos con tal de comparar si son falsos positivos.
        /// </summary>
        /// <param name="checkResult">PdfCheckResult para comparar los falsos positivos.</param>
        /// <returns></returns>
        public List <PdfTagPattern> ExtractToCheck(PdfCheckResult checkResult)
        {
            PdfTagExtractionResult result = new PdfTagExtractionResult()
            {
                Pdf          = checkResult.Pdf,
                MetadataType = Type.GetType(MetadataName)
            };

            _Converters = new Dictionary <Type, object>();

            IHierarchySet hierarchySet = GetHierarchySet();

            foreach (var page in checkResult.Pdf.PdfUnstructuredPages)
            {
                ExtractFromRectangles(page.WordGroups,
                                      result.MetadataType, hierarchySet, result, page.PdfPageN);

                ExtractFromRectangles(page.Lines,
                                      result.MetadataType, hierarchySet, result, page.PdfPageN, "LinesInfos");

                ExtractFromText(result.MetadataType, result, page, hierarchySet);

                ExtractFromColorFontText(page.ColorFontWordGroups,
                                         result.MetadataType, hierarchySet, result, page.PdfPageN);
            }

            result.Converters = _Converters;

            return(result.CheckWithRightMetadata(checkResult.InvoiceMetadata)); // Comprobamos que los patrones que pasemos como resultado hayan extraído el texto correctamente.
        }
        /// <summary>
        /// Ejecuta el proceso de extracción de metadatos
        /// en base a los patrones almacenados.
        /// </summary>
        /// <param name="pdfDocRectangles">rectángulos del pdf doc.</param>
        /// <param name="metadataType">Implementa IMetadata.</param>
        /// <param name="hierarchySet">Catálogo de jerarquías.</param>
        /// <param name="result">Resultados.</param>
        /// <param name="pageNumber">Número de la página sobre la que se realiza la extracción.</param>
        /// <param name="sourceTypeName">Nombre de la fuente.</param>
        private void ExtractFromRectangles(List <PdfTextRectangle> pdfDocRectangles,
                                           Type metadataType, IHierarchySet hierarchySet, PdfTagExtractionResult result,
                                           int pageNumber,
                                           string sourceTypeName = "WordGroupsInfos")
        {
            foreach (var pdfDocRectangle in pdfDocRectangles)
            {
                foreach (var pattern in PdfPatterns)
                {
                    if (pattern.PdfPageN == pageNumber || pattern.IsLastPage) // Comprobamos que los patrones realicen la extracción sobre la página que les corresponde.
                                                                              // Se comprueba la última página porque en algunos documentos viene primero los albaranes y al final la factura.
                    {
                        if (pattern.SourceTypeName == sourceTypeName)
                        {
                            if (IsAlmostSameArea(pdfDocRectangle, pattern.PdfRectangle))
                            {
                                string               textInput       = pdfDocRectangle.Text;
                                PropertyInfo         pInf            = metadataType.GetProperty(pattern.MetadataItemName);
                                ITextParserHierarchy parserHierarchy = hierarchySet.GetParserHierarchy(pInf);

                                if (pInf.PropertyType == typeof(string))
                                {
                                    parserHierarchy.SetParserRegexPattern(0, pattern.RegexPattern);
                                }

                                dynamic converter = parserHierarchy.GetConverter(pattern.RegexPattern);

                                MatchCollection matches = Regex.Matches(pdfDocRectangle.Text, pattern.RegexPattern);

                                int p = pattern.Position;
                                int m = matches.Count;

                                string val = (pattern.Position < matches.Count) ?
                                             matches[pattern.Position].Value : null;

                                object pValue = null;

                                if (val != null && converter != null)
                                {
                                    pValue = converter.Convert(val);
                                }

                                if (pValue != null && !PdfCompare.IsZeroNumeric(pValue))
                                {
                                    result.AddResult(pattern, pValue);
                                    if (!_Converters.ContainsKey(pInf.PropertyType))
                                    {
                                        _Converters.Add(pInf.PropertyType, converter);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Ejecuta el proceso de extracción de metadatos
        /// en base a los patrones almacenados.
        /// </summary>
        /// <param name="pdfDocRectangles">rectángulos del pdf doc.</param>
        /// <param name="metadataType">Implementa IMetadata.</param>
        /// <param name="hierarchySet">Catálogo de jerarquías.</param>
        /// <param name="result">Resultados.</param>
        /// <param name="sourceTypeName">Nombre de la fuente.</param>
        private void ExtractFromRectangles(List <PdfTextRectangle> pdfDocRectangles,
                                           Type metadataType, IHierarchySet hierarchySet, PdfTagExtractionResult result,
                                           string sourceTypeName = "WordGroupsInfos")
        {
            foreach (var pdfDocRectangle in pdfDocRectangles)
            {
                foreach (var pattern in PdfPatterns)
                {
                    if (pattern.SourceTypeName == sourceTypeName)
                    {
                        if (IsAlmostSameArea(pdfDocRectangle, pattern.PdfRectangle))
                        {
                            string               textInput       = pdfDocRectangle.Text;
                            PropertyInfo         pInf            = metadataType.GetProperty(pattern.MetadataItemName);
                            ITextParserHierarchy parserHierarchy = hierarchySet.GetParserHierarchy(pInf);

                            if (pInf.PropertyType == typeof(string))
                            {
                                parserHierarchy.SetParserRegexPattern(0, pattern.RegexPattern);
                            }

                            dynamic converter = parserHierarchy.GetConverter(pattern.RegexPattern);

                            MatchCollection matches = Regex.Matches(pdfDocRectangle.Text, pattern.RegexPattern);

                            string val = (pattern.Position < matches.Count) ?
                                         matches[pattern.Position].Value : null;

                            object pValue = null;

                            if (val != null && converter != null)
                            {
                                pValue = converter.Convert(val);
                            }

                            if (pValue != null && !PdfCompare.IsZeroNumeric(pValue))
                            {
                                result.AddResult(pattern, pValue);
                                if (!_Converters.ContainsKey(pInf.PropertyType))
                                {
                                    _Converters.Add(pInf.PropertyType, converter);
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Ejecuta los patrones de extracción de textos
        /// almacenados.
        /// </summary>
        /// <param name="pdf">Archivo PDF sobre el que extraer.</param>
        /// <returns></returns>
        public PdfTagExtractionResult Extract(PdfUnstructuredDoc pdf)
        {
            PdfTagExtractionResult result = new PdfTagExtractionResult()
            {
                Pdf          = pdf,
                MetadataType = Type.GetType(MetadataName)
            };

            _Converters = new Dictionary <Type, object>();

            IHierarchySet hierarchySet = GetHierarchySet();

            PdfPatternsPage = new Dictionary <int, List <PdfTagPattern> >();
            foreach (PdfTagPattern pattern in PdfPatterns) // Evitar que los bucles de extracción recorran siempre todos los patrones idependientemente del número de página.
            {
                if (PdfPatternsPage.ContainsKey(pattern.PdfPageN))
                {
                    PdfPatternsPage[pattern.PdfPageN].Add(pattern);
                }
                else
                {
                    PdfPatternsPage[pattern.PdfPageN] = new List <PdfTagPattern>()
                    {
                        pattern
                    }
                };
            }

            foreach (var page in pdf.PdfUnstructuredPages)
            {
                ExtractFromRectangles(page.WordGroups,
                                      result.MetadataType, hierarchySet, result, page.PdfPageN);

                ExtractFromRectangles(page.Lines,
                                      result.MetadataType, hierarchySet, result, page.PdfPageN, "LinesInfos");

                ExtractFromText(result.MetadataType, result, page, hierarchySet);

                ExtractFromColorFontText(page.ColorFontWordGroups,
                                         result.MetadataType, hierarchySet, result, page.PdfPageN);
            }

            result.Converters = _Converters;

            result.GetMetadata();

            return(result);
        }
        /// <summary>
        /// Ejecuata la extracción basada en limites
        /// textuales.
        /// </summary>
        /// <param name="metadataType">Tipo de la clase que implementa IMetadata.</param>
        /// <param name="result">Resultado de extracción.</param>
        /// <param name="page">PdfUnstructuredPage del doc. pdf.</param>
        /// <param name="hierarchySet">Catálogo de jerarquías.</param>
        private void ExtractFromText(Type metadataType,
                                     PdfTagExtractionResult result, PdfUnstructuredPage page,
                                     IHierarchySet hierarchySet)
        {
            foreach (var pattern in PdfPatterns)
            {
                if (pattern.PdfPageN == page.PdfPageN || pattern.IsLastPage) // Comprobamos que los patrones realicen la extracción sobre la página que les corresponde.
                                                                             // Se comprueba la última página porque en algunos documentos viene primero los albaranes y al final la factura.
                {
                    if (pattern.SourceTypeName == "PdfTextInfos")
                    {
                        foreach (Match match in Regex.Matches(page.PdfText, pattern.RegexPattern))
                        {
                            PropertyInfo pInf = metadataType.GetProperty(pattern.MetadataItemName);

                            if (pInf.PropertyType == typeof(string))
                            {
                                result.AddResult(pattern, match.Value);
                            }
                            else
                            {
                                dynamic converter = null;

                                if (_Converters.ContainsKey(pInf.PropertyType))
                                {
                                    converter = _Converters[pInf.PropertyType];
                                }
                                else
                                {
                                    ITextParserHierarchy parserHierarchy = hierarchySet.GetParserHierarchy(pInf);
                                    converter = parserHierarchy.GetConverter(pInf.PropertyType);

                                    if (converter == null)
                                    {
                                        Type converterGenType = typeof(Converter <>).MakeGenericType(pInf.PropertyType);
                                        converter = Activator.CreateInstance(converterGenType);
                                    }
                                }

                                object pValue = converter.Convert(match.Value);
                                result.AddResult(pattern, pValue);
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Ejecuata la extracción basada en limites
        /// textuales.
        /// </summary>
        /// <param name="metadataType">Tipo de la clase que implementa IMetadata.</param>
        /// <param name="result">Resultado de extracción.</param>
        /// <param name="page">PdfUnstructuredPage del doc. pdf.</param>
        private void ExtractFromText(Type metadataType,
                                     PdfTagExtractionResult result, PdfUnstructuredPage page,
                                     IHierarchySet hierarchySet)
        {
            foreach (var pattern in PdfPatterns)
            {
                if (pattern.SourceTypeName == "PdfTextInfos")
                {
                    foreach (Match match in Regex.Matches(page.PdfText, pattern.RegexPattern))
                    {
                        PropertyInfo pInf = metadataType.GetProperty(pattern.MetadataItemName);

                        if (pInf.PropertyType == typeof(string))
                        {
                            result.AddResult(pattern, match.Value);
                        }
                        else
                        {
                            dynamic converter = null;

                            if (_Converters.ContainsKey(pInf.PropertyType))
                            {
                                converter = _Converters[pInf.PropertyType];
                            }
                            else
                            {
                                ITextParserHierarchy parserHierarchy = hierarchySet.GetParserHierarchy(pInf);
                                converter = parserHierarchy.GetConverter(pInf.PropertyType);
                                if (converter == null)
                                {
                                    Type converterGenType = typeof(Converter <>).MakeGenericType(pInf.PropertyType);
                                    converter = Activator.CreateInstance(converterGenType);
                                }
                            }
                            object pValue = converter.Convert(match.Value);
                            result.AddResult(pattern, pValue);
                        }
                    }
                }
            }
        }
Beispiel #10
0
        /// <summary>
        /// Devuelve las coincidencias entre los datos
        /// del pdf, y los metadatos facilitados.
        /// <code lang="C#">
        ///         // Partiendo de una entrada de datos no estructurados de pdf
        ///         PdfUnstructuredDoc pdf = new PdfUnstructuredDoc(@"C:\ProgramData\PdfTagger\Inbox\0000021101.pdf");
        ///
        ///         // y de un conjunto de datos estructurados
        ///         InvoiceMetadata metadata = new InvoiceMetadata();
        ///
        ///         metadata.InvoiceNumber = "1 / 33050";
        ///         metadata.BuyerPartyID = "ES - A12070330";
        ///         metadata.IssueDate = new DateTime(2017, 11, 30);
        ///         metadata.GrossAmount = 3646.50m;
        ///         metadata.TaxesOutputsBase01 = 3013.64m;
        ///         metadata.TaxesOutputsRate01 = 21m;
        ///         metadata.TaxesOutputsAmount01 = 632.86m;
        ///
        ///         PdfCompareResult compareResult = PdfCompare.Compare(new BusinessHierarchySet(), pdf, metadata);
        /// </code>
        /// <code lang="VB">
        ///       ' Partiendo de una entrada de datos no estructurados de pdf
        ///        Dim pdf As PdfUnstructuredDoc = New PdfUnstructuredDoc(@"C:\ProgramData\PdfTagger\Inbox\0000021101.pdf")
        ///
        ///        ' y de un conjunto de datos estructurados
        ///        Dim metadata As InvoiceMetadata = New InvoiceMetadata()
        ///
        ///        metadata.InvoiceNumber = "1 / 33050"
        ///        metadata.BuyerPartyID = "ES - A12070330"
        ///        metadata.IssueDate = New Date(2017, 11, 30)
        ///        metadata.GrossAmount = CDec(3646.5)
        ///        metadata.TaxesOutputsBase01 = CDec(3013.64)
        ///        metadata.TaxesOutputsRate01 = 21
        ///        metadata.TaxesOutputsAmount01 = CDec(632.86)
        ///
        ///        Dim compareResult As PdfCompareResult = PdfCompare.Compare(New BusinessHierarchySet(), pdf, metadata)
        /// </code>
        /// </summary>
        /// <param name="hierarchySet">Catalogo de jerarquías de analizadores
        /// por tipo. La operación utilizara para comparar cada tipo de variable
        /// el parser obtenido del catálogo. La comparación se irá ejecutando
        /// por cada uno de los parsers según su orden en la jerarquía, hasta
        /// que se encuentre un valor coincidente o se llegue al final
        /// de la jerarquía.</param>
        /// <param name="pdf">Instancia de la clase PdfUnstructuredDoc fruto
        /// del análisis y obtención de los datos no estructurados de un pdf.</param>
        /// <param name="metadata">Datos estructurados a comparar con los
        /// datos no estructurados obtenidos del pdf.</param>
        /// <returns>Instancia de la clase PdfCompareResult con
        /// los resultados obtenidos de la comparación.</returns>
        public static PdfCompareResult Compare(IHierarchySet hierarchySet,
                                               PdfUnstructuredDoc pdf, IMetadata metadata)
        {
            PdfCompareResult compareResult = new PdfCompareResult(pdf, metadata, hierarchySet);

            foreach (PropertyInfo pInf in metadata.GetType().GetProperties())
            {
                object pValue = pInf.GetValue(metadata);

                // Obtengo la jerarquía de analizadores
                ITextParserHierarchy parserHierarchy = hierarchySet.GetParserHierarchy(pInf);

                if (pInf.PropertyType == typeof(string))
                {
                    parserHierarchy.SetParserRegexPattern(0, TxtRegex.Replace($"{pValue}"));
                }

                // Recorro todos los datos del pdf que quiero comparar
                if (parserHierarchy != null && pValue != null && !IsZeroNumeric(pValue))
                {
                    foreach (var page in pdf.PdfUnstructuredPages)
                    {
                        // Grupos de palabras
                        foreach (var wordGroup in page.WordGroups)
                        {
                            foreach (var match in parserHierarchy.GetMatches(pValue, wordGroup.Text))
                            {
                                compareResult.WordGroupsInfos.Add(new PdfCompareInfo(pdf, page, wordGroup, match, pInf, null));
                            }
                        }

                        // Grupos de líneas
                        foreach (var line in page.Lines)
                        {
                            foreach (var match in parserHierarchy.GetMatches(pValue, line.Text))
                            {
                                compareResult.LinesInfos.Add(new PdfCompareInfo(pdf, page, line, match, pInf, null));
                            }
                        }

                        // Grupos de texto con porpiedades como el color de la fuente
                        foreach (var textString in page.TextStringGroups)
                        {
                            foreach (var match in parserHierarchy.GetMatches(pValue, textString.Text))
                            {
                                PdfClownTextString tsNA = new PdfClownTextString(textString.Text, textString.ColorFill, textString.ColorStroke, textString.FontType, textString.FontSize)
                                {
                                    Rectangle = textString.Rectangle,
                                    Type      = "NA"
                                };

                                PdfClownTextString tsX = new PdfClownTextString(textString.Text, textString.ColorFill, textString.ColorStroke, textString.FontType, textString.FontSize)
                                {
                                    Type      = "X",
                                    Rectangle = textString.Rectangle
                                };

                                PdfClownTextString tsY = new PdfClownTextString(textString.Text, textString.ColorFill, textString.ColorStroke, textString.FontType, textString.FontSize)
                                {
                                    Type      = "Y",
                                    Rectangle = textString.Rectangle
                                };

                                compareResult.TextStringInfos.Add(new PdfCompareInfo(pdf, page, null, match, pInf, tsNA));
                                compareResult.TextStringInfos.Add(new PdfCompareInfo(pdf, page, null, match, pInf, tsX));
                                compareResult.TextStringInfos.Add(new PdfCompareInfo(pdf, page, null, match, pInf, tsY));
                            }
                        }


                        foreach (var match in parserHierarchy.GetMatches(pValue, page.PdfText))
                        {
                            Type       txtBoundMatchGenType = typeof(TextBoundMatch <>).MakeGenericType(pInf.PropertyType);
                            ITextMatch txtBoundMatch        = (ITextMatch)Activator.CreateInstance(txtBoundMatchGenType, match);
                            ITextMatch txtBoundMatchSoft    = (ITextMatch)Activator.CreateInstance(txtBoundMatchGenType, match);
                            (txtBoundMatchSoft as ITextBoundMatch).UseLengthOnPatternDigitReplacement = false;

                            if (txtBoundMatch.Pattern != null)
                            {
                                dynamic converter = parserHierarchy.GetConverter(match.Pattern);

                                // Límites contextuales
                                if (IsAllMatchesOK(txtBoundMatch, page, pValue, converter))
                                {
                                    compareResult.PdfTextInfos.Add(
                                        new PdfCompareInfo(pdf, page, null, txtBoundMatch, pInf, null));
                                }

                                // Límites contextuales menos estrictos
                                if (IsAllMatchesOK(txtBoundMatchSoft, page, pValue, converter))
                                {
                                    compareResult.PdfTextInfos.Add(
                                        new PdfCompareInfo(pdf, page, null, txtBoundMatchSoft, pInf, null));
                                }
                            }
                        }
                    }
                }
            }

            return(compareResult);
        }
        /// <summary>
        /// Ejecuta el proceso de extracción de metadatos
        /// en base a los patrones almacenados.
        /// </summary>
        /// <param name="pdfDocColorFontText">Rectángulos del pdf doc con color, tamaño y nombre de fuente.</param>
        /// <param name="metadataType">Implementa IMetadata.</param>
        /// <param name="hierarchySet">Catálogo de jerarquías.</param>
        /// <param name="result">Resultados.</param>
        /// <param name="pageNumber">Número de la página sobre la que se realiza la extracción.</param>
        private void ExtractFromColorFontText(List <PdfColorFontTextRectangle> pdfDocColorFontText,
                                              Type metadataType, IHierarchySet hierarchySet, PdfTagExtractionResult result,
                                              int pageNumber)
        {
            string sourceTypeName = "ColorFontWordGroupsInfos";

            foreach (var pdfDocColorFontWord in pdfDocColorFontText)
            {
                foreach (var pattern in PdfPatterns)
                {
                    if (pattern.PdfPageN == pageNumber || pattern.IsLastPage) // Comprobamos que los patrones realicen la extracción sobre la página que les corresponde.
                                                                              // Se comprueba la última página porque en algunos documentos viene primero los albaranes y al final la factura.
                    {
                        if (pattern.SourceTypeName == sourceTypeName)
                        {
                            if (pdfDocColorFontWord.FillColor == pattern.FillColor &&
                                pdfDocColorFontWord.StrokeColor == pattern.StrokeColor &&
                                pdfDocColorFontWord.FontName == pattern.FontName &&
                                pdfDocColorFontWord.FontSize.ToString() == pattern.FontSize
                                ) // Comprobamos que tienen el mismo color, tamaño y nombre de fuente.
                                  // No comprobamos el CFType porque cuando llega aquí, pdfDocColorFontWord no tiene un CFType asignado aún.
                            {
                                if (pattern.CFType.Equals("NA") ||
                                    (pattern.CFType.Equals("X") && (pattern.PdfRectangle.Llx.Equals(pdfDocColorFontWord.Llx) || pattern.PdfRectangle.Urx.Equals(pdfDocColorFontWord.Urx))) ||
                                    (pattern.CFType.Equals("Y") && (pattern.PdfRectangle.Lly.Equals(pdfDocColorFontWord.Lly) || pattern.PdfRectangle.Ury.Equals(pdfDocColorFontWord.Ury))))
                                {
                                    string               textInput       = pdfDocColorFontWord.Text;
                                    PropertyInfo         pInf            = metadataType.GetProperty(pattern.MetadataItemName);
                                    ITextParserHierarchy parserHierarchy = hierarchySet.GetParserHierarchy(pInf);

                                    if (pInf.PropertyType == typeof(string))
                                    {
                                        parserHierarchy.SetParserRegexPattern(0, pattern.RegexPattern);
                                    }

                                    dynamic converter = parserHierarchy.GetConverter(pattern.RegexPattern);

                                    MatchCollection matches = Regex.Matches(pdfDocColorFontWord.Text, pattern.RegexPattern);

                                    string val = (pattern.Position < matches.Count) ?
                                                 matches[pattern.Position].Value : null;

                                    object pValue = null;

                                    if (val != null && converter != null)
                                    {
                                        pValue = converter.Convert(val);
                                    }

                                    if (pValue != null && !PdfCompare.IsZeroNumeric(pValue))
                                    {
                                        result.AddResult(pattern, pValue);
                                        if (!_Converters.ContainsKey(pInf.PropertyType))
                                        {
                                            _Converters.Add(pInf.PropertyType, converter);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }