/// <summary> /// Processes the attributes. /// </summary> /// <param name="attributeConcepts"> /// The attribute concepts. /// </param> /// <param name="attributes"> /// The attributes. /// </param> /// <exception cref="SdmxSemmanticException"> /// Unknown attribute ' + attribute + ' reported in the data. This attribute is /// not defined by the data structure definition /// </exception> private void ProcessAttributes(ICollection<string> attributeConcepts, ICollection<IKeyValue> attributes) { foreach (var attributeConcept in attributeConcepts) { string conceptValue; if ((this._attributeValues.TryGetValue(attributeConcept, out conceptValue) || this._rolledUpAttributes.TryGetValue(attributeConcept, out conceptValue)) && conceptValue != null) { IKeyValue kv = new KeyValueImpl(conceptValue, attributeConcept); attributes.Add(kv); } } if (this._attributeValues.Count != attributes.Count) { string attribute = this._attributeValues.Keys.FirstOrDefault(s => !attributeConcepts.Contains(s)); if (attribute != null) { throw new SdmxSemmanticException("Unknown attribute '" + attribute + "' reported in the data. This attribute is not defined by the data structure definition"); } } }
/// <summary> /// Processes the series node. /// </summary> /// <exception cref="SdmxSemmanticException">Missing series key value</exception> /// <returns> /// The <see cref="IKeyable" />. /// </returns> protected override IKeyable ProcessSeriesNode() { // clear values this._keyValues.Clear(); this._attributeValues.Clear(); TimeFormat timeFormat = null; string timeValue = null; ISet<string> unknownConcepts = new HashSet<string>(StringComparer.Ordinal); for (int i = 0; i < this.Parser.AttributeCount; i++) { this.Parser.MoveToAttribute(i); string attributeId = this.GetComponentId(this.Parser.LocalName); string attributeValue = this.Parser.Value; if (string.Equals(attributeId, this._timeConcept)) { timeValue = attributeValue; timeFormat = DateUtil.GetTimeFormatOfDate(timeValue); } else if (this._dimensionConcepts.Contains(attributeId)) { this._keyValues.Add(attributeId, attributeValue); } else if (this._seriesAttributes.Contains(attributeId)) { this._attributeValues.Add(attributeId, attributeValue); } else if (this.DatasetPositionInternal == Api.Constants.DatasetPosition.ObservationAsSeries) { // This attribute was not found as a series level attribute, it could still be an observation level attribute // But this is only allowed if we are processing this series node as a FLAT obs node which is both an obs and key // In which case this attributeName could be an observation attribute, the primary measure, or the time concept if (!this._observationAttributes.Contains(attributeId) && !attributeId.Equals(this._primaryMeasureConcept) && !attributeId.Equals(this._timeConcept)) { unknownConcepts.Add(attributeId); } } else { unknownConcepts.Add(attributeId); } } var key = new List<IKeyValue>(); foreach (var dimensionConcept in this._dimensionConcepts) { string conceptValue; if (!this._keyValues.TryGetValue(dimensionConcept, out conceptValue) && !this._rolledUpAttributes.TryGetValue(dimensionConcept, out conceptValue)) { if (this.DatasetHeader.Action != DatasetActionEnumType.Delete) { if (this.IsTimeSeries || !this.CrossSectionConcept.Equals(dimensionConcept)) { throw new SdmxSemmanticException(string.Format("Missing series key value for concept: {0}", dimensionConcept)); } } } else { IKeyValue kv = new KeyValueImpl(conceptValue, dimensionConcept); key.Add(kv); } } if (unknownConcepts.Count > 0) { // NOTE this is a simplified version of the corresponding Java code. string series = string.Join(", ", key.Select(kv => kv.Code)); string unknownConcept = string.Join(", ", unknownConcepts); throw new SdmxSemmanticException(string.Format(CultureInfo.InvariantCulture, "Unknown concept(s) '{0}' reported for series : {1}", unknownConcept, series)); } var attributes = new List<IKeyValue>(); try { this.ProcessAttributes(this._seriesAttributes, attributes); } catch (SdmxException e) { throw new SdmxException("Error while processing series attributes", e); } // Clear values this._keyValues.Clear(); this._attributeValues.Clear(); if (this.IsTimeSeries) { if (this.DatasetPositionInternal == Api.Constants.DatasetPosition.Series) { // NOTE Java has a try catch because it needs change the exception to a runtime exception. In .NET we should not do this because // all exceptions in C# are run time exceptions. Doing it makes it harder to diagnose problems. while (this.RunAheadParser.Read()) { var nodeType = this.RunAheadParser.NodeType; string localName = this.RunAheadParser.LocalName; if (nodeType == XmlNodeType.Element) { if (ElementNameTable.Obs.Is(localName)) { this.ProcessObservation(this.RunAheadParser); timeFormat = DateUtil.GetTimeFormatOfDate(this._obsTime); break; } } else if (nodeType == XmlNodeType.EndElement) { if (ElementNameTable.Series.Is(localName)) { break; } } } } this.CurrentKeyValue = this.CreateKeyable(key, attributes, timeFormat); } else { this.CurrentKeyValue = this.CreateKeyable(key, attributes, timeFormat, timeValue); } if (this.DatasetPositionInternal == Api.Constants.DatasetPosition.ObservationAsSeries) { this.CurrentObs = this.ProcessObsNode(this.Parser); // unused variable in java 1.1.4. Possibly a bug in Java SdmxSource 1.1.4? timeFormat = this.CurrentObs.ObsTimeFormat; } this._attributeValues.Clear(); return this.CurrentKeyValue; }
/// <summary> /// Processes the group node. /// </summary> /// <returns> /// The <see cref="IKeyable" />. /// </returns> protected override IKeyable ProcessGroupNode() { // clear values this._keyValues.Clear(); this._attributes.Clear(); for (int i = 0; i < this.Parser.AttributeCount; i++) { this.Parser.MoveToAttribute(i); string attributeName = this.GetComponentId(this.Parser.LocalName); string attributeValue = this.Parser.Value; string ns = this.Parser.NamespaceURI; if (XmlConstants.XmlSchemaNS.Equals(ns) && "type".Equals(attributeName)) { this.GroupId = attributeValue.Contains(":") ? attributeValue.Split(':')[1] : attributeValue; } else { if (this._dimensionConcepts.Contains(attributeName)) { this._keyValues.Add(attributeName, attributeValue); } else { this._attributeValues.Add(attributeName, attributeValue); } } } var key = new List<IKeyValue>(); var attributes = new List<IKeyValue>(); List<string> conceptList; if (!this._groupConcepts.TryGetValue(this.GroupId, out conceptList)) { throw new SdmxSemmanticException(string.Format(CultureInfo.InvariantCulture, "Data Structure '{0}' does not contain group '{1}'", this.CurrentDsdInternal, this.GroupId)); } foreach (var groupConcept in conceptList) { string conceptValue; if (!this._keyValues.TryGetValue(groupConcept, out conceptValue) && !this._rolledUpAttributes.TryGetValue(groupConcept, out conceptValue)) { throw new SdmxSemmanticException(string.Format(CultureInfo.InvariantCulture, "No value found in data for group '{0}' and concept '{1}'. ", this.GroupId, groupConcept)); } var kv = new KeyValueImpl(conceptValue, groupConcept); key.Add(kv); } try { this.ProcessAttributes(this._groupAttributeConcepts[this.GroupId], attributes); } catch (SdmxSemmanticException e) { throw new SdmxSemmanticException(string.Format("Error while processing group attributes for group '{0}' ", this.GroupId), e); } this._keyValues.Clear(); this._attributeValues.Clear(); return this.CurrentKeyValue = this.CreateKeyable(key, attributes, this.GroupId); }
/// <summary> /// Builds the current observation. /// </summary> private void BuildCurrentObservation() { var attributes = new List<IKeyValue>(); foreach (var key in this._observationAttributes) { IKeyValue keyValue = new KeyValueImpl(key.Value, key.Key); attributes.Add(keyValue); } IKeyValue crossSectionValue = null; if (this._crossSectionalObservation != null) { crossSectionValue = new KeyValueImpl(this._crossSectionalObservation, this._availableMeasureDimensions[0]); } this._currentObs = new ObservationImpl(this._currentKey, this._currentKey.ObsTime, this._observationValue, attributes, crossSectionValue); }
/// <summary> /// Builds the current key. /// </summary> private void BuildCurrentKey() { var conceptKeys = new List<IKeyValue>(); foreach (var key in this._dataSetConcepts) { IKeyValue keyValue = new KeyValueImpl(key.Value, key.Key); conceptKeys.Add(keyValue); } foreach (var key in this._groupConcepts) { IKeyValue keyValue = new KeyValueImpl(key.Value, key.Key); conceptKeys.Add(keyValue); } foreach (var key in this._sectionConcepts) { IKeyValue keyValue = new KeyValueImpl(key.Value, key.Key); conceptKeys.Add(keyValue); } foreach (var key in this._observationConcepts) { IKeyValue keyValue = new KeyValueImpl(key.Value, key.Key); conceptKeys.Add(keyValue); } var attributeKeys = new List<IKeyValue>(); foreach (var key in this._dataSetAttributes) { IKeyValue keyValue = new KeyValueImpl(key.Value, key.Key); attributeKeys.Add(keyValue); } foreach (var key in this._groupAttributes) { IKeyValue keyValue = new KeyValueImpl(key.Value, key.Key); attributeKeys.Add(keyValue); } foreach (var key in this._sectionAttributes) { IKeyValue keyValue = new KeyValueImpl(key.Value, key.Key); attributeKeys.Add(keyValue); } if (!string.IsNullOrWhiteSpace(this._timeDimensionId) && !string.IsNullOrWhiteSpace(this._obsTime)) { TimeFormat timeFormat = DateUtil.GetTimeFormatOfDate(this._obsTime); this._currentKey = new KeyableImpl(this._dataflow, this._currentDsd, conceptKeys, attributeKeys, timeFormat, this._timeDimensionId, this._obsTime); } else { this._currentKey = new KeyableImpl(this._dataflow, this._currentDsd, conceptKeys, attributeKeys, string.Empty); } }
/// <summary> /// Processes the OBS node. /// </summary> /// <param name="parser"> /// The parser. /// </param> /// <returns> /// The <see cref="IObservation"/>. /// </returns> protected override IObservation ProcessObsNode(XmlReader parser) { string obsDimension = null; string obsValue = null; IList<IKeyValue> attributes = null; string text = null; while (parser.Read()) { var nodeType = parser.NodeType; if (nodeType == XmlNodeType.Element) { string nodeName = parser.LocalName; if (ElementNameTable.ObsDimension.Is(nodeName)) { obsDimension = parser.GetAttribute(AttributeNameTable.value); } else if (ElementNameTable.ObsValue.Is(nodeName)) { obsValue = parser.GetAttribute(AttributeNameTable.value); } else if (ElementNameTable.Attributes.Is(nodeName)) { attributes = this.GetKeyValues(ElementNameTable.Attributes); } } else if (nodeType == XmlNodeType.Text) { text = parser.Value; } else if (nodeType == XmlNodeType.EndElement) { string nodeName = parser.LocalName; if (ElementNameTable.Time.Is(nodeName)) { obsDimension = text; } else if (ElementNameTable.Obs.Is(nodeName)) { break; } } } obsDimension = this.GetComponentId(obsDimension); try { if (this.IsTimeSeries) { return new ObservationImpl(this.CurrentKeyValue, obsDimension, obsValue, attributes); } if (obsDimension == null) { throw new SdmxSemmanticException( string.Format("Error while processing observation for series '{0}' , missing required cross sectional concept value '{1}'", this.CurrentKey, this.CrossSectionConcept)); } IKeyValue crossSection = new KeyValueImpl(obsDimension, this.CrossSectionConcept); return new ObservationImpl(this.CurrentKeyValue, this.CurrentKeyValue.ObsTime, obsValue, attributes, crossSection); } catch (SdmxException) { throw; } catch (Exception th) { if (this.CurrentKey != null) { throw new SdmxException("Error while processing observation for key " + this.CurrentKeyValue, th); } throw new SdmxException("Error while processing observation"); } }