Skip to content

Commit 857a022

Browse files
Merge pull request #150 from PxTools/feature/meta-id-revisited
System for metaid link creation
2 parents 47ad09e + 0c3c88f commit 857a022

12 files changed

Lines changed: 880 additions & 2 deletions

File tree

‎PCAxis.Serializers.sln‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
44
VisualStudioVersion = 17.1.32319.34
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serializers", "PCAxis.Serializers\PCAxis.Serializers.csproj", "{7ACACE11-9150-47AC-B82C-6BBFCB912610}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PCAxis.Serializers", "PCAxis.Serializers\PCAxis.Serializers.csproj", "{7ACACE11-9150-47AC-B82C-6BBFCB912610}"
77
EndProject
88
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "UnitTests\UnitTests.csproj", "{8DCFDCAD-E8E0-4602-BA54-769CB0B39662}"
99
EndProject
59 KB
Loading
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace PCAxis.Serializers.Util.MetaId
2+
{
3+
/// <summary>
4+
/// Link to a metadata system. "Output"-class for meta-id.
5+
/// </summary>
6+
public class Link
7+
{
8+
9+
/// <summary>
10+
/// Link text
11+
/// </summary>
12+
public string Label { get; set; }
13+
14+
/// <summary>
15+
/// Link (URL)
16+
/// </summary>
17+
public string Url { get; set; }
18+
19+
/// <summary>
20+
/// Content-type type like "text/html"
21+
/// </summary>
22+
public string Type { get; set; }
23+
24+
/// <summary>
25+
/// What type of information is the link to: about-statistics, statistics-homepage, definition-classification, definition-value ,,,
26+
/// </summary>
27+
public string Relation { get; set; }
28+
}
29+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System;
2+
using System.Configuration;
3+
4+
using PCAxis.Serializers.Util.MetaId;
5+
6+
namespace PCAxis.Serializers.Util.Metaid
7+
{
8+
/// <summary>
9+
/// Class with template for a link
10+
/// </summary>
11+
internal class LinkTemplate
12+
{
13+
private readonly string _metaSysId;
14+
15+
public LinkTemplate(string metaSysId, string textFormat, string linkFormat, string linkType, string linkRelation)
16+
{
17+
if (string.IsNullOrWhiteSpace(metaSysId))
18+
{
19+
throw new ConfigurationErrorsException("MetaId config: metaSystem element must have non null id");
20+
}
21+
22+
if (string.IsNullOrWhiteSpace(linkFormat))
23+
{
24+
throw new ConfigurationErrorsException("MetaId config: urlStringFormat must have non null value");
25+
}
26+
27+
this.LinkTextFormat = textFormat;
28+
this.LinkUrlFormat = linkFormat;
29+
this.LinkType = linkType;
30+
this.LinkRelation = linkRelation;
31+
this._metaSysId = metaSysId;
32+
}
33+
34+
35+
public bool Match(string metaIdString)
36+
{
37+
return metaIdString.StartsWith(MetaSysId);
38+
}
39+
40+
/// <summary>
41+
/// Format of the link text
42+
/// </summary>
43+
public string LinkTextFormat { get; }
44+
45+
/// <summary>
46+
/// Format of the link (URL)
47+
/// </summary>
48+
public string LinkUrlFormat { get; }
49+
50+
/// <summary>
51+
/// Content-type Type
52+
/// </summary>
53+
public string LinkType { get; }
54+
public string LinkRelation { get; }
55+
56+
public string MetaSysId => _metaSysId;
57+
58+
/// <summary>
59+
/// Returns a completed/ready/formatted Link
60+
/// </summary>
61+
/// <param name="textParams"></param>
62+
/// <param name="linkParams"></param>
63+
/// <returns></returns>
64+
public Link GetFormattedLink(string[] textParams, string[] linkParams)
65+
{
66+
Link link = new Link();
67+
link.Relation = this.LinkRelation;
68+
link.Type = this.LinkType;
69+
70+
link.Url = String.Format(this.LinkUrlFormat, linkParams);
71+
link.Label = String.Format(this.LinkTextFormat, textParams);
72+
return link;
73+
}
74+
}
75+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System.Collections.Generic;
2+
3+
namespace PCAxis.Serializers.Util.Metaid
4+
{
5+
enum AttachmentLevel { onTable, onVariable, onValue }
6+
7+
internal class LinkTemplatesHolder : Dictionary<string, Dictionary<string, List<LinkTemplate>>>
8+
{
9+
//string attachmentLevel, string language, List<LinkTemplate>
10+
11+
public void Add(AttachmentLevel attachmentLevel, string language, LinkTemplate linkTemplate)
12+
{
13+
string level_string = attachmentLevel.ToString();
14+
15+
if (!this.ContainsKey(level_string))
16+
{
17+
this[level_string] = new Dictionary<string, List<LinkTemplate>>();
18+
}
19+
20+
if (!this[level_string].ContainsKey(language))
21+
{
22+
this[level_string][language] = new List<LinkTemplate>();
23+
}
24+
25+
this[level_string][language].Add(linkTemplate);
26+
}
27+
28+
29+
public List<LinkTemplate> GetTemplates(AttachmentLevel attachmentLevel, string language)
30+
{
31+
string level_string = attachmentLevel.ToString();
32+
33+
if (!this.ContainsKey(level_string))
34+
{
35+
return new List<LinkTemplate>();
36+
}
37+
38+
if (!this[level_string].ContainsKey(language))
39+
{
40+
return new List<LinkTemplate>();
41+
}
42+
43+
return this[level_string][language];
44+
45+
}
46+
47+
48+
49+
}
50+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Xml;
4+
5+
using PCAxis.Serializers.Util.Metaid;
6+
7+
namespace PCAxis.Serializers.Util.MetaId
8+
{
9+
/// <summary>
10+
/// Class that encapsulates a metaid.config file containing link-definitions to metadata systems, and has methodsw that resolves a "raw" meta-id string to Links.
11+
/// </summary>
12+
public static class MetaIdResolverStatic
13+
{
14+
15+
#region "Private fields"
16+
17+
/// <summary>
18+
/// Configuration file
19+
/// </summary>
20+
private static XmlDocument _xdoc;
21+
22+
/// <summary>
23+
/// Logging to Log4Net
24+
/// </summary>
25+
private static readonly log4net.ILog _logger = log4net.LogManager.GetLogger(typeof(MetaIdResolverStatic));
26+
27+
/// <summary>
28+
/// Character that separates the systems within a META-ID
29+
/// </summary>
30+
private static readonly char[] _systemSeparator = { ',', ' ' };
31+
32+
/// <summary>
33+
/// Character that separates the parameters within a system META-ID
34+
/// </summary>
35+
private static readonly char[] _paramSeparator = { ':' };
36+
37+
/// <summary>
38+
/// Holds all data loaded from config, reshuffled so using it easy.
39+
/// </summary>
40+
private static readonly LinkTemplatesHolder holder = LoadConfiguration("metaid.config");
41+
42+
#endregion
43+
44+
45+
/// <summary>
46+
/// Load metadata.config file
47+
/// </summary>
48+
/// <param name="configurationFile">Path to the configuration file</param>
49+
/// <returns>True if the configuration file was successfully loaded, else false</returns>
50+
private static LinkTemplatesHolder LoadConfiguration(string configurationFile)
51+
{
52+
//It is ok to not use metaid
53+
if (!System.IO.File.Exists(configurationFile))
54+
{
55+
_logger.WarnFormat("Metaid configuration file '{0}' does not exist in the folder where the dlls are ...", configurationFile);
56+
return new LinkTemplatesHolder();
57+
}
58+
59+
_xdoc = new XmlDocument();
60+
_xdoc.Load(configurationFile);
61+
62+
LinkTemplatesHolder myOut = new LinkTemplatesHolder();
63+
64+
// Table-level
65+
LoadConfigurationSection(AttachmentLevel.onTable, myOut);
66+
67+
// Variable-level
68+
LoadConfigurationSection(AttachmentLevel.onVariable, myOut);
69+
70+
// Value-level
71+
LoadConfigurationSection(AttachmentLevel.onValue, myOut);
72+
73+
return myOut;
74+
}
75+
76+
/// <summary>
77+
/// Load sub section of the configuration file
78+
/// </summary>
79+
/// <param name="section">Name of the section</param>
80+
/// <param name="dictionary">Dictionary to store section data in</param>
81+
/// <returns></returns>
82+
private static void LoadConfigurationSection(AttachmentLevel attachmentLevel, LinkTemplatesHolder holder)
83+
{
84+
// Find all metaSystem nodes in section
85+
string section = attachmentLevel.ToString();
86+
87+
string xpath = "/metaId/" + section + "/metaSystem";
88+
XmlNodeList xmlnodes = _xdoc.SelectNodes(xpath);
89+
90+
foreach (XmlNode sysNode in xmlnodes)
91+
{
92+
string sysId = sysNode.Attributes["id"].Value;
93+
94+
// Find all language nodes for the system
95+
xpath = ".//relationalGroup";
96+
XmlNodeList relationalGroupNodes = sysNode.SelectNodes(xpath);
97+
98+
foreach (XmlNode relationalGroupNode in relationalGroupNodes)
99+
{
100+
string linkType = relationalGroupNode.Attributes["type"].Value;
101+
string linkRelation = relationalGroupNode.Attributes["relation"].Value;
102+
103+
// Find all language nodes for the system
104+
xpath = ".//link";
105+
XmlNodeList linkNodes = relationalGroupNode.SelectNodes(xpath);
106+
107+
foreach (XmlNode linkNode in linkNodes)
108+
{
109+
string pxLang = linkNode.Attributes["pxLang"].Value;
110+
string labelStringFormat = linkNode.Attributes["labelStringFormat"].Value;
111+
string urlStringFormat = linkNode.Attributes["urlStringFormat"].Value;
112+
113+
LinkTemplate temp = new LinkTemplate(sysId, labelStringFormat, urlStringFormat, linkType, linkRelation);
114+
holder.Add(attachmentLevel, pxLang, temp);
115+
}
116+
}
117+
}
118+
}
119+
120+
121+
/// <summary>
122+
/// Create links
123+
/// </summary>
124+
/// <param name="metaIdList">META-ID one or more</param>
125+
/// <param name="templates">templates for Language and attachmentlevel</param>
126+
/// <param name="textParams">0,1 or 2 text parameters, depending on attachmentleve</param>
127+
/// <returns></returns>
128+
private static List<Link> GetLinks(string metaIdList, List<LinkTemplate> templates, string[] textParams)
129+
{
130+
List<Link> myOut = new List<Link>();
131+
132+
if (templates.Count == 0)
133+
{
134+
return myOut;
135+
}
136+
137+
string[] metaIds = metaIdList.Split(_systemSeparator, StringSplitOptions.RemoveEmptyEntries);
138+
139+
foreach (string metaId in metaIds)
140+
{
141+
foreach (LinkTemplate template in templates)
142+
{
143+
if (!template.Match(metaId))
144+
{
145+
break;
146+
}
147+
148+
string rawParamsString = metaId.Replace(template.MetaSysId, "");
149+
string[] linkParams = rawParamsString.Split(_paramSeparator, StringSplitOptions.RemoveEmptyEntries);
150+
151+
myOut.Add(template.GetFormattedLink(textParams, linkParams));
152+
153+
}
154+
}
155+
156+
return myOut;
157+
}
158+
159+
160+
161+
#region "Implementation of IMetaIdProvider"
162+
163+
164+
public static List<Link> GetTableLinks(string metaIdField, string language)
165+
{
166+
string[] textParams = new string[] { };
167+
return GetLinks(metaIdField, holder.GetTemplates(AttachmentLevel.onTable, language), textParams);
168+
}
169+
170+
public static List<Link> GetVariableLinks(string metaIdField, string language, string variableLabel)
171+
{
172+
string[] textParams = new string[] { variableLabel };
173+
return GetLinks(metaIdField, holder.GetTemplates(AttachmentLevel.onVariable, language), textParams);
174+
}
175+
176+
public static List<Link> GetValueLinks(string metaIdField, string language, string variableLabel, string valueLabel)
177+
{
178+
string[] textParams = new string[] { variableLabel, valueLabel };
179+
return GetLinks(metaIdField, holder.GetTemplates(AttachmentLevel.onValue, language), textParams);
180+
}
181+
#endregion
182+
183+
}
184+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# The Meta-id system
2+
String replacement system to turn things like
3+
4+
"STATISTICS:aku"
5+
6+
into
7+
```
8+
"relation": "statistics-homepage"
9+
"href": "https://www.ssb.no/en/aku"
10+
"label": "Statistics homepage"
11+
"type": "text/html"
12+
```
13+
14+
using a file called metaid.config. There a fragment:
15+
```
16+
<metaSystem id="STATISTICS">
17+
<relationalGroup relation="statistics-homepage" type="text/html">
18+
...
19+
<link pxLang="en" labelStringFormat="Statistics homepage" urlStringFormat="https://www.ssb.no/en/{0}" />
20+
</relationalGroup>
21+
....
22+
```
23+
24+
The usecase is to provide content in pxweb2gui for the areas shown in Figma_infomation_defs.png
25+
26+
![Information pane in figma](Figma_infomation_defs.png?raw=true)
27+
28+
29+
The client is the mapper that maps a paxiom to jsonstat2 for the metadata endpoint in pxwebapi, which produces something like what is shown in example.json.
30+
31+
32+
Figma_infomation_defs.png:
33+
to get content for "area-1" , look for relation="statistics-homepage" on root
34+
to get content for "area-2" , look for relation="about-statistics" on root
35+
to get content for "area-3" , loop variables and look for relations starting with "definition-"
36+
37+

0 commit comments

Comments
 (0)