private static IEnumerable<OpenXmlPackageValidationEventArgs> ValidateDataPartReferenceRelationships(OpenXmlPartContainer container, FileFormatVersions version)
 {
     // At current, only media / audio / video reference. There are all [0, unbounded].
     // So just check whether the reference is allowed.
     foreach (var dataPartReference in container.DataPartReferenceRelationships)
     {
         if (!container.GetPartMetadata().DataPartReferenceConstraints.TryGetValue(dataPartReference.RelationshipType, out var constraintRule))
         {
             yield return new OpenXmlPackageValidationEventArgs(container)
             {
                 MessageId = "DataPartReferenceIsNotAllowed",
                 PartClassName = dataPartReference.RelationshipType,
                 Part = container.ThisOpenXmlPart,
                 SubPart = null,
                 DataPartReferenceRelationship = dataPartReference,
             };
         }
     }
 }
        /// <summary>
        /// Validates the package (do not validate the xml content in each part).
        /// </summary>
        /// <param name="container">The Open XML container to validate</param>
        /// <param name="version">Version to validate against</param>
        /// <param name="processedParts">Parts already processed.</param>
        private IEnumerable<OpenXmlPackageValidationEventArgs> ValidateInternal(OpenXmlPartContainer container, FileFormatVersions version, Dictionary<OpenXmlPart, bool> processedParts)
        {
            foreach (var result in ValidateDataPartReferenceRelationships(container, version))
            {
                yield return result;
            }

            // count all parts of same type
            var partOccurs = new Dictionary<string, int>(StringComparer.Ordinal);

            foreach (var part in container.ChildrenRelationshipParts.Values)
            {
                if (partOccurs.TryGetValue(part.RelationshipType, out int occurs))
                {
                    partOccurs[part.RelationshipType] = occurs + 1;
                }
                else
                {
                    partOccurs.Add(part.RelationshipType, 1);
                }

                if (!(container is ExtendedPart) &&
                    !container.GetPartMetadata().PartConstraints.ContainsRelationship(part.RelationshipType) &&
                    part.IsInVersion(version))
                {
                    yield return new OpenXmlPackageValidationEventArgs(container)
                    {
                        MessageId = "PartIsNotAllowed",
                        PartClassName = part.RelationshipType,
                        Part = container.ThisOpenXmlPart,
                        SubPart = part,
                    };
                }

                // if the part is not defined in this version, then should not report error, just treat it as ExtendedPart.
            }

            foreach (var constraintRulePair in container.GetPartMetadata().PartConstraints)
            {
                var relatinshipType = constraintRulePair.Key;
                var constraintRule = constraintRulePair.Value;

                // validate the required parts
                if (constraintRule.MinOccursIsNonZero

                    // only check rules apply to the specified version.
                    && version.AtLeast(constraintRule.FileFormat))
                {
                    // must have one
                    if (container.GetSubPart(relatinshipType) is null)
                    {
                        yield return new OpenXmlPackageValidationEventArgs(container)
                        {
                            MessageId = "RequiredPartDoNotExist",
                            PartClassName = constraintRule.PartClassName,
                            Part = container.ThisOpenXmlPart,
                        };
                    }
                }

                // check for parts MaxOccursGreatThanOne=false, but do have multiple instance
                if (!constraintRule.MaxOccursGreatThanOne

                    // only check rules apply to the specified version.
                    && version.AtLeast(constraintRule.FileFormat))
                {
                    if (partOccurs.TryGetValue(relatinshipType, out int occurs))
                    {
                        if (occurs > 1)
                        {
                            yield return new OpenXmlPackageValidationEventArgs(container)
                            {
                                MessageId = "OnlyOnePartAllowed",
                                PartClassName = constraintRule.PartClassName,
                                Part = container.ThisOpenXmlPart,
#if DEBUG
                                SubPart = container.GetSubPart(relatinshipType),
#endif
                            };
                        }
                    }
                }
            }

            foreach (var part in container.ChildrenRelationshipParts.Values)
            {
                if (!processedParts.ContainsKey(part))
                {
                    if (!(part is ExtendedPart))
                    {
                        if (container.GetPartMetadata().PartConstraints.TryGetValue(part.RelationshipType, out var rule))
                        {
                            if (version.AtLeast(rule.FileFormat))
                            {
                                // validate content type
                                if (rule.PartContentType is not null && part.ContentType != rule.PartContentType)
                                {
                                    var message = SR.Format(ExceptionMessages.InvalidContentTypePart, rule.PartContentType);

                                    yield return new OpenXmlPackageValidationEventArgs(container)
                                    {
                                        Message = message,
                                        MessageId = "InvalidContentTypePart",
                                        SubPart = part,
                                        Part = container.ThisOpenXmlPart,
                                    };
                                }
                            }
                            else
                            {
                                // if the part is not defined in this version, then should not report error, just treat it as ExtendedPart.
                            }
                        }
                    }
#if DEBUG
                    else
                    {
                        // check the relationship type
                        if (part.RelationshipType.StartsWith(@"http://schemas.openxmlformats.org", StringComparison.OrdinalIgnoreCase))
                        {
                            yield return new OpenXmlPackageValidationEventArgs(container)
                            {
                                MessageId = "ExtendedPartIsOpenXmlPart",
                                SubPart = part,
                                Part = container.ThisOpenXmlPart,
                            };
                        }
                    }
#endif
                    processedParts.Add(part, true);

                    foreach (var result in ValidateInternal(part, version, processedParts))
                    {
                        yield return result;
                    }
                }
            }
        }