/// <summary> /// Validate the stream contents represent a valid CycloneDX XML document. /// </summary> /// <param name="xmlStream"></param> /// <param name="specificationVersion"></param> /// <returns></returns> public static Models.ValidationResult Validate(Stream xmlStream, SpecificationVersion specificationVersion) { var validationMessages = new List <string>(); var schemaVersionString = specificationVersion.ToString().Substring(1).Replace('_', '.'); var expectedNamespaceUri = $"http://cyclonedx.org/schema/bom/{schemaVersionString}"; var assembly = typeof(Validator).GetTypeInfo().Assembly; using (var schemaStream = assembly.GetManifestResourceStream($"CycloneDX.Core.Schemas.bom-{schemaVersionString}.xsd")) using (var spdxStream = assembly.GetManifestResourceStream("CycloneDX.Core.Schemas.spdx.xsd")) { var settings = new XmlReaderSettings(); settings.Schemas.Add(XmlSchema.Read(schemaStream, null)); settings.Schemas.Add(XmlSchema.Read(spdxStream, null)); settings.ValidationType = ValidationType.Schema; using (var reader = XmlReader.Create(xmlStream, settings)) { var document = new XmlDocument(); try { document.Load(reader); if (document.DocumentElement.NamespaceURI != expectedNamespaceUri) { validationMessages.Add($"Invalid namespace URI: expected {expectedNamespaceUri} actual {document.DocumentElement.NamespaceURI}"); } } catch (XmlSchemaValidationException exc) { var lineInfo = ((IXmlLineInfo)reader); if (lineInfo.HasLineInfo()) { validationMessages.Add($"Validation failed at line number {lineInfo.LineNumber} and position {lineInfo.LinePosition}: {exc.Message}"); } else { validationMessages.Add($"Validation failed at position {xmlStream.Position}: {exc.Message}"); } } catch (XmlException exc) { validationMessages.Add(exc.Message); } } } return(new Models.ValidationResult { Valid = validationMessages.Count == 0, Messages = validationMessages }); }
private static string SchemaVersionResourceFilenameString(SpecificationVersion schemaVersion) => schemaVersion.ToString().Substring(1).Replace('_', '.');