public bool SaveAs(string fn, bool writeFreshly = false, PreferredFormat prefFmt = PreferredFormat.None, MemoryStream useMemoryStream = null) { Console.WriteLine("SaveAs: " + fn); if (fn.ToLower().EndsWith(".xml")) { // save only XML this.fn = fn; try { using (var s = new StreamWriter(this.fn)) { // TODO: use aasenv serialzers here! var serializer = new XmlSerializer(typeof(AdminShell.AdministrationShellEnv)); var nss = new XmlSerializerNamespaces(); nss.Add("xsi", System.Xml.Schema.XmlSchema.InstanceNamespace); nss.Add("aas", "http://www.admin-shell.io/aas/2/0"); nss.Add("IEC61360", "http://www.admin-shell.io/IEC61360/2/0"); serializer.Serialize(s, this.aasenv, nss); } } catch (Exception ex) { throw (new Exception(string.Format("While writing AAS {0} at {1} gave: {2}", fn, AdminShellUtil.ShortLocation(ex), ex.Message))); } return(true); } if (fn.ToLower().EndsWith(".json")) { // save only JSON // this funcitonality is a initial test this.fn = fn; try { using (var sw = new StreamWriter(fn)) { // TODO: use aasenv serialzers here! sw.AutoFlush = true; JsonSerializer serializer = new JsonSerializer() { NullValueHandling = NullValueHandling.Ignore, ReferenceLoopHandling = ReferenceLoopHandling.Serialize, Formatting = Newtonsoft.Json.Formatting.Indented }; using (JsonWriter writer = new JsonTextWriter(sw)) { serializer.Serialize(writer, this.aasenv); } } } catch (Exception ex) { throw (new Exception(string.Format("While writing AAS {0} at {1} gave: {2}", fn, AdminShellUtil.ShortLocation(ex), ex.Message))); } return(true); } if (fn.ToLower().EndsWith(".aasx")) { // save package AASX try { // we want existing contents to be preserved, but no possiblity to change file name // therefore: copy file to new name, re-open! // fn could be changed, therefore close "old" package first if (this.openPackage != null) { // ReSharper disable EmptyGeneralCatchClause try { this.openPackage.Close(); if (!writeFreshly) { if (this.tempFn != null) { System.IO.File.Copy(this.tempFn, fn); } else { System.IO.File.Copy(this.fn, fn); } } } catch { } // ReSharper enable EmptyGeneralCatchClause this.openPackage = null; } // approach is to utilize the existing package, if possible. If not, create from scratch Package package = null; if (useMemoryStream != null) { package = Package.Open(useMemoryStream, (writeFreshly) ? FileMode.Create : FileMode.OpenOrCreate); } else { package = Package.Open((this.tempFn != null) ? this.tempFn : fn, (writeFreshly) ? FileMode.Create : FileMode.OpenOrCreate); } this.fn = fn; // get the origin from the package PackagePart originPart = null; var xs = package.GetRelationshipsByType("http://www.admin-shell.io/aasx/relationships/aasx-origin"); foreach (var x in xs) { if (x.SourceUri.ToString() == "/") { originPart = package.GetPart(x.TargetUri); break; } } if (originPart == null) { // create, as not existing originPart = package.CreatePart(new Uri("/aasx/aasx-origin", UriKind.RelativeOrAbsolute), System.Net.Mime.MediaTypeNames.Text.Plain, CompressionOption.Maximum); using (var s = originPart.GetStream(FileMode.Create)) { var bytes = System.Text.Encoding.ASCII.GetBytes("Intentionally empty."); s.Write(bytes, 0, bytes.Length); } package.CreateRelationship(originPart.Uri, TargetMode.Internal, "http://www.admin-shell.io/aasx/relationships/aasx-origin"); } // get the specs from the package PackagePart specPart = null; PackageRelationship specRel = null; xs = originPart.GetRelationshipsByType("http://www.admin-shell.io/aasx/relationships/aas-spec"); foreach (var x in xs) { specRel = x; specPart = package.GetPart(x.TargetUri); break; } // check, if we have to change the spec part if (specPart != null && specRel != null) { var name = System.IO.Path.GetFileNameWithoutExtension(specPart.Uri.ToString()).ToLower().Trim(); var ext = System.IO.Path.GetExtension(specPart.Uri.ToString()).ToLower().Trim(); if ((ext == ".json" && prefFmt == PreferredFormat.Xml) || (ext == ".xml" && prefFmt == PreferredFormat.Json) || (name.StartsWith("aasenv-with-no-id"))) { // try kill specpart // ReSharper disable EmptyGeneralCatchClause try { originPart.DeleteRelationship(specRel.Id); package.DeletePart(specPart.Uri); } catch { } finally { specPart = null; specRel = null; } // ReSharper enable EmptyGeneralCatchClause } } if (specPart == null) { // create, as not existing var frn = "aasenv-with-no-id"; if (this.aasenv.AdministrationShells.Count > 0) { frn = this.aasenv.AdministrationShells[0].GetFriendlyName() ?? frn; } var aas_spec_fn = "/aasx/#/#.aas"; if (prefFmt == PreferredFormat.Json) { aas_spec_fn += ".json"; } else { aas_spec_fn += ".xml"; } aas_spec_fn = aas_spec_fn.Replace("#", "" + frn); specPart = package.CreatePart(new Uri(aas_spec_fn, UriKind.RelativeOrAbsolute), System.Net.Mime.MediaTypeNames.Text.Xml, CompressionOption.Maximum); originPart.CreateRelationship(specPart.Uri, TargetMode.Internal, "http://www.admin-shell.io/aasx/relationships/aas-spec"); } // now, specPart shall be != null! if (specPart.Uri.ToString().ToLower().Trim().EndsWith("json")) { using (var s = specPart.GetStream(FileMode.Create)) { JsonSerializer serializer = new JsonSerializer(); serializer.NullValueHandling = NullValueHandling.Ignore; serializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; serializer.Formatting = Newtonsoft.Json.Formatting.Indented; using (var sw = new StreamWriter(s)) { using (JsonWriter writer = new JsonTextWriter(sw)) { serializer.Serialize(writer, this.aasenv); } } } } else { using (var s = specPart.GetStream(FileMode.Create)) { var serializer = new XmlSerializer(typeof(AdminShell.AdministrationShellEnv)); var nss = new XmlSerializerNamespaces(); nss.Add("xsi", System.Xml.Schema.XmlSchema.InstanceNamespace); nss.Add("aas", "http://www.admin-shell.io/aas/2/0"); nss.Add("IEC61360", "http://www.admin-shell.io/IEC61360/2/0"); serializer.Serialize(s, this.aasenv, nss); } } // there might be pending files to be deleted (first delete, then add, in case of identical files in both categories) foreach (var psfDel in pendingFilesToDelete) { // try find an existing part for that file .. var found = false; // normal files xs = specPart.GetRelationshipsByType("http://www.admin-shell.io/aasx/relationships/aas-suppl"); foreach (var x in xs) { if (x.TargetUri == psfDel.uri) { // try to delete specPart.DeleteRelationship(x.Id); package.DeletePart(psfDel.uri); found = true; break; } } // thumbnails xs = package.GetRelationshipsByType("http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"); foreach (var x in xs) { if (x.TargetUri == psfDel.uri) { // try to delete package.DeleteRelationship(x.Id); package.DeletePart(psfDel.uri); found = true; break; } } if (!found) { throw (new Exception($"Not able to delete pending file {psfDel.uri} in saving package {fn}")); } } // after this, there are no more pending for delete files pendingFilesToDelete.Clear(); // write pending supplementary files foreach (var psfAdd in pendingFilesToAdd) { // make sure .. if ((psfAdd.sourceLocalPath == null && psfAdd.sourceGetBytesDel == null) || psfAdd.location != AdminShellPackageSupplementaryFile.LocationType.AddPending) { continue; } // normal file? if (psfAdd.specialHandling == AdminShellPackageSupplementaryFile.SpecialHandlingType.None || psfAdd.specialHandling == AdminShellPackageSupplementaryFile.SpecialHandlingType.EmbedAsThumbnail) { // try find an existing part for that file .. PackagePart filePart = null; if (psfAdd.specialHandling == AdminShellPackageSupplementaryFile.SpecialHandlingType.None) { xs = specPart.GetRelationshipsByType("http://www.admin-shell.io/aasx/relationships/aas-suppl"); foreach (var x in xs) { if (x.TargetUri == psfAdd.uri) { filePart = package.GetPart(x.TargetUri); break; } } } if (psfAdd.specialHandling == AdminShellPackageSupplementaryFile.SpecialHandlingType.EmbedAsThumbnail) { xs = package.GetRelationshipsByType("http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"); foreach (var x in xs) { if (x.SourceUri.ToString() == "/" && x.TargetUri == psfAdd.uri) { filePart = package.GetPart(x.TargetUri); break; } } } if (filePart == null) { // determine mimeType var mimeType = psfAdd.useMimeType; // reconcile mime if (mimeType == null && psfAdd.sourceLocalPath != null) { mimeType = AdminShellPackageEnv.GuessMimeType(psfAdd.sourceLocalPath); } // still null? if (mimeType == null) { // see: https://stackoverflow.com/questions/6783921/which-mime-type-to-use-for-a-binary-file-thats-specific-to-my-program mimeType = "application/octet-stream"; } // create new part and link filePart = package.CreatePart(psfAdd.uri, mimeType, CompressionOption.Maximum); if (psfAdd.specialHandling == AdminShellPackageSupplementaryFile.SpecialHandlingType.None) { specPart.CreateRelationship(filePart.Uri, TargetMode.Internal, "http://www.admin-shell.io/aasx/relationships/aas-suppl"); } if (psfAdd.specialHandling == AdminShellPackageSupplementaryFile.SpecialHandlingType.EmbedAsThumbnail) { package.CreateRelationship(filePart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"); } } // now should be able to write using (var s = filePart.GetStream(FileMode.Create)) { if (psfAdd.sourceLocalPath != null) { var bytes = System.IO.File.ReadAllBytes(psfAdd.sourceLocalPath); s.Write(bytes, 0, bytes.Length); } if (psfAdd.sourceGetBytesDel != null) { var bytes = psfAdd.sourceGetBytesDel(); if (bytes != null) { s.Write(bytes, 0, bytes.Length); } } } } } // after this, there are no more pending for add files pendingFilesToAdd.Clear(); // flush and close package.Flush(); this.openPackage = null; package.Close(); // if in temp fn, close the package, copy to original fn, re-open the package if (this.tempFn != null) { try { package.Close(); System.IO.File.Copy(this.tempFn, this.fn, overwrite: true); this.openPackage = Package.Open(this.tempFn, FileMode.OpenOrCreate); } catch (Exception ex) { throw (new Exception(string.Format("While write AASX {0} indirectly at {1} gave: {2}", fn, AdminShellUtil.ShortLocation(ex), ex.Message))); } } } catch (Exception ex) { throw (new Exception(string.Format("While write AASX {0} at {1} gave: {2}", fn, AdminShellUtil.ShortLocation(ex), ex.Message))); } return(true); } // Don't know to handle throw (new Exception(string.Format($"Not able to handle {fn}."))); }
//Annotations // Procedure: // 1. find submodel node // 2. create submodel node as submodel // 3. find children of submodel node // 4. create children of submodel node -> a (SubmodelElement) // 4.1. find children of a // 4.2. create children of a -> b (SubmodelElement) // 4.2.1. find children of b // ... // 4.3. set a as SubmodelElement of submodel // 5. add Submodel // // // most Methods are built the same way: // 1. iterate through all References of the node // 2. check that the ReferenceType is not HasTypeDefinition // 3. check for the Type or BrowseName public static AdminShellNS.AdminShellPackageEnv Import(UANodeSet model) { thePackageEnv = new AdminShellNS.AdminShellPackageEnv(); InformationModel = model; //Initialize everything needed AdminShell.AdministrationShellEnv env = thePackageEnv.AasEnv; var aas = new AdminShell.AdministrationShell(); aas.views = new Views(); aas.views.views = new List <View>(); env.AdministrationShells.Add(aas); //search for the root Node var root = getRoot(); //see Annotations if (root != null) { foreach (Reference _ref in root.References) { if (_ref.ReferenceType == "HasComponent") { var node = findNode(_ref.Value); //create Submodel if (getTypeDefinition(node) == "1:AASSubmodelType") { var submodel = createSubmodel((UAObject)node); if (submodel != null) { //add Submodel and its SubmodelRef env.Submodels.Add(submodel); var smr = new AdminShell.SubmodelRef(); smr.Keys.Add( new AdminShell.Key( "Submodel", true, submodel.identification.idType, submodel.identification.id)); aas.submodelRefs.Add(smr); } } //create ConceptDictionary else if (getTypeDefinition(node) == "1:AASConceptDictionaryType") { createConceptDictionary((UAObject)node); } //create Asset else if (getTypeDefinition(node) == "1:AASAssetType") { Asset ass = createAsset(node); thePackageEnv.AasEnv.Assets.Add(ass); } //create Views else if (getTypeDefinition(node) == "1:AASViewType") { aas.views.views.Add(createView(node)); } //set DerivedFrom else if (node.BrowseName == "1:DerivedFrom") { List <Key> keys = addSemanticID(node); if (keys.Count > 0) { aas.derivedFrom = new AssetAdministrationShellRef(keys[0]); } } //create HasDataSpecification else if (node.BrowseName == "1:DataSpecification") { aas.hasDataSpecification = CreateHasDataSpecification(node); } //create AssetRef else if (node.BrowseName == "1:AssetRef") { aas.assetRef = createAssetRef(node); } else if (node.BrowseName == "1:Identification" && getTypeDefinition(node) == "1:AASIdentifierType") { aas.identification = createIdentification(node); } } else if (_ref.ReferenceType == "HasProperty") { var node = findNode(_ref.Value); if (node.BrowseName == "1:idShort") { var vari = (UAVariable)node; aas.idShort = vari.Value.InnerText; } } } } return(thePackageEnv); }