/// <summary> /// Examines the tags and merges duplicates together /// </summary> /// <remarks> /// This was added because Version#1 of the file would often have mixed results, such that there were two /// MyTag1 objects. One of the objects would have the PV and SP parameters and the other would have /// a OP parameter. This method will find those duplicates and "normalize" them so that there is only /// one instance containing all of the parameters. /// </remarks> private void Normalize() { Dictionary <string, HmiWebMetaData> normalizedTaglist = new Dictionary <string, HmiWebMetaData>(); foreach (HmiWebMetaData tag in Tags) { HmiWebMetaData normalizedTag = null; string key = tag.TagName.ToLower(); if (!normalizedTaglist.TryGetValue(key, out normalizedTag)) { normalizedTag = tag; normalizedTaglist.Add(key, normalizedTag); } else { //Add any parameters that need to be added. foreach (string parameter in tag.Parameters) { if (!normalizedTag.Parameters.Contains(parameter)) { normalizedTag.Parameters.Add(parameter); } } if (string.IsNullOrWhiteSpace(normalizedTag.FaceplatePartialFileName)) { normalizedTag.FaceplatePartialFileName = tag.FaceplatePartialFileName; } } //It seems like the Deserialize can't handle the "Parameters=""" properly. It thinks there //is a blank parameter. Remove it. if (normalizedTag.Parameters.Contains("")) { normalizedTag.Parameters.Remove(""); } } Tags = normalizedTaglist.Values.ToList(); }
/// <summary> /// Read the passed in HMIWeb graphic file (by loading into an HTML document), /// and write out all the tags to a metadata ".ucsparsed" file for quick searching. /// The file will not be created if one already exists and is newer than the HMIWeb file /// </summary> /// <param name="fullHmiWebGraphicFileName">The full HMIWeb graphics file name</param> /// <param name="infoMessages">Informational messages created as part of the parsing</param> /// <param name="errorMessages">Error messages created as a result of failing to parse the file</param> /// <returns> /// The contents of the HMIWeb Graphics file as it has been parsed and normalized. /// </returns> static public HmiWebParseFile ParseHmiWebGraphic(string fullHmiWebGraphicFileName, out List <string> infoMessages, out List <string> errorMessages) { infoMessages = new List <string>(); errorMessages = new List <string>(); //If the HMIWeb graphic doesn't exist, return immediately if (!File.Exists(fullHmiWebGraphicFileName)) { errorMessages.Add(string.Format("HMIWeb file {0} could not be opened by the search feature.", fullHmiWebGraphicFileName)); return(null); } HmiWebParseFile retVal = null; bool createFile = true; // Is true if the metadata file needs to be created string metadataFileName = fullHmiWebGraphicFileName + FileExtension; // Name of the metadata file //If the metadata file exists, we want to check to see if we need to re-create it or not. //We will re-create it if the the metadata file is older than the HMIWeb file if (File.Exists(metadataFileName)) { //File exists, we don't have to create it. createFile = File.GetLastWriteTime(fullHmiWebGraphicFileName) > File.GetLastWriteTime(metadataFileName); if (!createFile) { try { //Great. We can save time by just reading in the existing metadata file. retVal = HmiWebParseFile.Deserialize(metadataFileName); if (retVal != null && retVal.Version != HmiWebParseFile.Version3) { //Whoops - we need to upgrade the file. It was created with an older //version of the parser. retVal = null; //Setting to null will trigger a CreateFile = true below. } } catch (Exception ex) { //Failed to load the file. We'll log the message and then indicate that we need //to re-create the file since it is mostly likely in an unknown format. infoMessages.Add(string.Format("Failed to load '{0}'. The file will be re-created\n\n{1}", metadataFileName, ex.Message)); retVal = null; //Setting to null will trigger a CreateFile = true below. } finally { //If there was some problem loading the search file, we'll re-create it. if (retVal is null) { createFile = true; } } } } //If things have gone well, we have read in an existing metdata data file which will save us a lot of //time. But if the metadata file didn't exist, or there was some other error, we'll have to take //the more time consuming route and parse the HMIWeb graphic file. if (createFile) { try { //Read the entire HMIWeb file into memory string fileContents = File.ReadAllText(fullHmiWebGraphicFileName); //Put the text into an in-memory browser so that we can parse it. using (WebBrowser browser = new WebBrowser()) { browser.ScriptErrorsSuppressed = true; browser.DocumentText = fileContents; browser.Document.OpenNew(true); browser.Document.Write(fileContents); browser.Refresh(); HtmlDocument pHtmlDoc3 = browser.Document; //Create the HmiWebParseFile object that we will populate. retVal = new HmiWebParseFile(); //We are looking for something like the following ... //<DIV // tabIndex = -1 id = shape078 class=hsc.shape.1 linkType = "embedded" globalscripts = "" styleClass = "" numberOfShapesAnimated = "1" value = "1" // style="FONT-SIZE: 0px; TEXT-DECORATION: none; HEIGHT: 44px; FONT-FAMILY: Arial; WIDTH: 94px; POSITION: absolute; FONT-WEIGHT: 400; FONT-STYLE: normal; LEFT: 119px; TOP: 38px; BEHAVIOR: url(#HSCShapeLinkBehavior) url(#HSCShapeLinkBehavior#shapelinkanimator) url(#HDXVectorFactory#shapelink) url(#BindingBehavior); VISIBILITY: inherit" // hdxproperties="fillColorBlink:False;HDXBINDINGID:1;Height:44;lineColorBlink:False;Width:94;" // src = ".\Debutanizer_files\REGCTL_SIM2_U.sha" // parameters = "Text?Version:USO-R300;Point?tagname:11FC01;Text?FaceplateFile:Sim2\Faceplate\PID_REGCTL_SIM2_FP_U.htm;Parameter?cp_eudesc:EUDESC;Parameter?cp_mode:MODE;Parameter?cp_pntalm:PTINAL;Parameter?cp_pntalmack:ACKSTAT;Parameter?cp_pv:PV;Parameter?cp_pvformat:PVFORMAT;Parameter?cp_sp:SP;Parameter?cp_statetxt0:STATETXT0;Parameter?cp_statetxt1:STATETXT1;Parameter?cp_statetxt2:STATETXT2;Point?AssetName:11FC01@USD;" // > //Get all DIV tags from the HTML document HtmlElementCollection pDivCollection = pHtmlDoc3.GetElementsByTagName("DIV"); foreach (HtmlElement pDivElement in pDivCollection) { // Now get the "parameters" attribute string attributeValue = pDivElement.GetAttribute("parameters"); // Now find the "tagname" and "assetName" parameters and create XML element for each (if found) // Will be of the format ?tagname:11HC01; or ?AssetName:11HC01; string tagName = GetParameterValue(attributeValue, TagnameIdentifier); if (!string.IsNullOrWhiteSpace(tagName)) { HmiWebMetaData tagInfo = new HmiWebMetaData(tagName); //We have a tagname. If we have a faceplate, then we will potentially have a //trendable point ... which means that we want to search for the trendable parameters string faceplateFile = GetParameterValue(attributeValue, FaceplateFileIdentifier); if (!string.IsNullOrWhiteSpace(faceplateFile)) { //Store off the "short" faceplate name associated with this tag tagInfo.FaceplatePartialFileName = faceplateFile; bool foundPv = false; bool foundSp = false; //Look for the PV, SP, and OP parameters string pv = GetParameterValue(attributeValue, PVIdentifier); if (!string.IsNullOrWhiteSpace(pv)) { tagInfo.Parameters.Add(pv); foundPv = true; } string sp = GetParameterValue(attributeValue, SPIdentifier); if (!string.IsNullOrWhiteSpace(sp)) { tagInfo.Parameters.Add(sp); foundSp = true; } string op = GetParameterValue(attributeValue, OPIdentifier); if (!string.IsNullOrWhiteSpace(op)) { tagInfo.Parameters.Add(op); } else if (foundPv && foundSp) { //We are looking for trendable parameters. In many cases, the item on the main graphic //will display both PV and SP to the user. If the user clicks on the icon, it will //bring up a faceplate containing trending information for PV, SP, and OP. So if we //find something with both PV and SP, we'll automatically add OP. tagInfo.Parameters.Add("OP"); } } retVal.Tags.Add(tagInfo); } string assetName = GetParameterValue(attributeValue, AssetNameIdentifier); if (!string.IsNullOrWhiteSpace(assetName)) { retVal.Tags.Add(new HmiWebMetaData(assetName)); } } //Write the XML file & do cleanup ... but only if we have some valid information if (retVal.Tags.Count > 0) { string saveError = retVal.Save(metadataFileName); if (!string.IsNullOrEmpty(saveError)) { errorMessages.Add(saveError); } } } } catch (Exception) { errorMessages.Add(string.Format("Error:\nFailed to parse the HMIWeb file '{0}'\nConsequences:\nSearch results for this graphic will not be available.", fullHmiWebGraphicFileName)); } } return(retVal); }