コード例 #1
0
        /// <summary>
        /// Parse the JSON number to <see cref="CsdlExpressionBase"/>.
        /// </summary>
        /// <param name="element">The JSON value to parse.</param>
        /// <param name="context">The parser context.</param>
        /// <returns>null or the parsed <see cref="CsdlExpressionBase"/>.</returns>
        private static CsdlExpressionBase ParseNumberExpression(JsonElement element, JsonParserContext context)
        {
            Debug.Assert(element.ValueKind == JsonValueKind.Number);
            Debug.Assert(context != null);

            CsdlLocation location = context.Location();

            // Int64 can handle all these integer types
            if (element.TryGetInt64(out long longValue))
            {
                return(new CsdlConstantExpression(EdmValueKind.Integer, longValue.ToString(CultureInfo.InvariantCulture), location));
            }

            // Decimal goes ahead double
            if (element.TryGetDecimal(out decimal decimalValue))
            {
                return(new CsdlConstantExpression(EdmValueKind.Decimal, decimalValue.ToString(CultureInfo.InvariantCulture), location));
            }

            // Double
            if (element.TryGetDouble(out double doubleValue))
            {
                return(new CsdlConstantExpression(EdmValueKind.Floating, doubleValue.ToString(CultureInfo.InvariantCulture), location));
            }

            // Any others?
            // Report error for unknown number
            context.ReportError(EdmErrorCode.InvalidNumberType, Strings.CsdlJsonParser_InvalidJsonNumberType(element, context.Path));
            return(null);
        }
コード例 #2
0
        private static Version ParseVersion(JsonElement element, JsonParserContext context)
        {
            Debug.Assert(context != null);

            Version version    = null;
            string  strVersion = element.ParseAsString(context);

            if (context.IsSucceeded())
            {
                if (strVersion == "4.0")
                {
                    version = EdmConstants.EdmVersion4;
                }
                else if (strVersion == "4.01")
                {
                    version = EdmConstants.EdmVersion401;
                }

                // This document object MUST contain the member $Version.
                if (version == null)
                {
                    context.ReportError(EdmErrorCode.InvalidVersionNumber, Strings.CsdlJsonParser_InvalidCsdlVersion(context.Path));
                }
            }

            return(version);
        }
コード例 #3
0
        private static JsonDocument GetJsonDocument(ref Utf8JsonReader jsonReader, JsonParserContext context)
        {
            Debug.Assert(context != null);

            try
            {
                JsonDocument.TryParseValue(ref jsonReader, out JsonDocument jsonDocument);
                return(jsonDocument);
            }
            catch (JsonException jsonEx)
            {
                StringBuilder sb = new StringBuilder(context.Source != null ? context.Source : "$");
                sb.Append(" LineNumber:");
                sb.Append(jsonEx.LineNumber != null ? jsonEx.LineNumber.Value.ToString(CultureInfo.InvariantCulture) : "N/A");

                sb.Append(" BytePositionInLine:");
                sb.Append(jsonEx.BytePositionInLine != null ? jsonEx.BytePositionInLine.Value.ToString(CultureInfo.InvariantCulture) : "N/A");

                sb.Append(" Path:");
                sb.Append(jsonEx.Path != null ? jsonEx.Path : "N/A");

                sb.Append(" ActualMessage:");
                sb.Append(jsonEx.Message != null ? jsonEx.Message : "N/A");

                context.ReportError(EdmErrorCode.InvalidJson, sb.ToString());
                return(null);
            }
        }
コード例 #4
0
        /// <summary>
        /// Parse the record expression expression using <see cref="JsonElement"/>.
        /// </summary>
        /// <param name="element">The input JSON element.</param>
        /// <param name="context">The parser context.</param>
        /// <returns>the built record expression.</returns>
        private static CsdlRecordExpression ParseRecordExpression(JsonElement element, JsonParserContext context)
        {
            Debug.Assert(context != null);

            // A record expression MAY specify the structured type of its result, which MUST be an entity type or complex type in scope.
            // If not explicitly specified, the type is derived from the expression’s context

            // The type of a record expression is represented as the @type control information
            // for example: "@type": "https://example.org/vocabs/person#org.example.person.Manager",
            // So far, ODL doesn't support the type "@type" with relative path, only supports like "#Model.VipCustomer", or without #
            // for 4.0, this name MUST be prefixed with the hash symbol (#);
            // or non-OData 4.0 payloads, built-in primitive type values SHOULD be represented without the hash symbol,
            // but consumers of 4.01 or greater payloads MUST support values with or without the hash symbol.

            CsdlTypeReference typeReference = null;

            if (element.TryGetProperty("@type", out JsonElement typeValue))
            {
                // Try to build the type. The type should be "Complex type" or "Entity Type".
                string typeName = typeValue.ProcessProperty("@type", context, (e, c) => e.ParseAsString(c));
                int    index    = typeName.IndexOf('#');
                if (index >= 0)
                {
                    typeName = typeName.Substring(index + 1); // remove the "#"
                }

                typeReference = new CsdlNamedTypeReference(typeName, true, context.Location());
            }

            IList <CsdlPropertyValue> propertyValues = new List <CsdlPropertyValue>();

            element.ParseAsObject(context, (propertyName, propertyValue) =>
            {
                // skips the @type, because it's processed above.
                if (propertyName == "@type")
                {
                    return;
                }

                // It MAY contain annotations for itself and its members. Annotations for record members are prefixed with the member name.
                // So far, it's not supported. So report non-fatal error for all the annotations on record.
                if (propertyName.IndexOf('@') != -1)
                {
                    context.ReportError(EdmErrorCode.UnsupportedElement, Strings.CsdlJsonParser_UnsupportedJsonMember(context.Path));
                    return;
                }

                CsdlExpressionBase propertyValueExpression = ParseExpression(propertyValue, context);
                propertyValues.Add(new CsdlPropertyValue(propertyName, propertyValueExpression, context.Location()));
            });

            return(new CsdlRecordExpression(typeReference, propertyValues, context.Location()));
        }
コード例 #5
0
        /// <summary>
        /// Parse the <see cref="JsonElement"/> to a <see cref="IEdmIncludeAnnotations"/>.
        /// </summary>
        /// <param name="element">The input JSON element.</param>
        /// <param name="context">The parser context.</param>
        /// <returns>null or parsed <see cref="IEdmIncludeAnnotations"/>.</returns>
        internal static IEdmIncludeAnnotations ParseIncludeAnnotations(JsonElement element, JsonParserContext context)
        {
            // Each item in $IncludeAnnotations is an object.
            if (!element.ValidateValueKind(JsonValueKind.Object, context))
            {
                return(null);
            }

            string termNamespace   = null;
            string qualifier       = null;
            string targetNamespace = null;

            element.ParseAsObject(context, (propertyName, propertyValue) =>
            {
                // Array items are objects that MUST contain the member $Namespace and MAY contain the member $Alias.
                switch (propertyName)
                {
                case "$TermNamespace":
                    // The value of $TermNamespace is a namespace.
                    termNamespace = propertyValue.ParseAsString(context);
                    break;

                case "$Qualifier":
                    // The value of $Qualifier is a simple identifier.
                    qualifier = propertyValue.ParseAsString(context);
                    break;

                case "$TargetNamespace":
                    // The value of $TargetNamespace is a namespace.
                    targetNamespace = propertyValue.ParseAsString(context);
                    break;

                default:
                    // The item objects MAY contain annotations. However, IEdmIncludeAnnotations doesn't support to have annotations.
                    context.ReportError(EdmErrorCode.UnexpectedElement,
                                        Strings.CsdlJsonParser_UnexpectedJsonMember(context.Path, propertyValue.ValueKind));
                    break;
                }
            });

            return(new EdmIncludeAnnotations(termNamespace, qualifier, targetNamespace));
        }
コード例 #6
0
        /// <summary>
        /// Parse the <see cref="JsonElement"/> to a <see cref="IEdmReference"/>.
        /// </summary>
        /// <param name="url">The reference Url string.</param>
        /// <param name="element">The input JSON element.</param>
        /// <param name="context">The parser context.</param>
        /// <returns>null or parsed <see cref="IEdmReference"/>.</returns>
        internal static IEdmReference ParseReference(string url, JsonElement element, JsonParserContext context)
        {
            // The value of each reference object is an object.
            if (!element.ValidateValueKind(JsonValueKind.Object, context))
            {
                return(null);
            }

            IList <IEdmInclude>            includes           = null;
            IList <IEdmIncludeAnnotations> includeAnnotations = null;

            element.ParseAsObject(context, (propertyName, propertyValue) =>
            {
                // The reference object MAY contain the members $Include and $IncludeAnnotations as well as annotations.
                switch (propertyName)
                {
                case "$Include":
                    // The value of $Include is an array.
                    // Array items are objects that MUST contain the member $Namespace and MAY contain the member $Alias.
                    includes = propertyValue.ParseAsArray(context, ParseInclude);
                    break;

                case "$IncludeAnnotations":
                    // The value of $IncludeAnnotations is an array.
                    // Array items are objects that MUST contain the member $TermNamespace and MAY contain the members $Qualifier and $TargetNamespace.
                    includeAnnotations = propertyValue.ParseAsArray(context, ParseIncludeAnnotations);
                    break;

                default:
                    // The reference objects MAY contain annotations.However, EdmReference doesn't support annotation.
                    // So, skip the annotation.
                    context.ReportError(EdmErrorCode.UnexpectedElement, Strings.CsdlJsonParser_UnexpectedJsonMember(context.Path, propertyValue.ValueKind));
                    break;
                }
            });

            EdmReference edmReference = new EdmReference(new Uri(url, UriKind.RelativeOrAbsolute));

            includes.ForEach(i => edmReference.AddInclude(i));
            includeAnnotations.ForEach(i => edmReference.AddIncludeAnnotations(i));
            return(edmReference);
        }
コード例 #7
0
        /// <summary>
        /// Parse the <see cref="CsdlExpressionBase"/> from the <see cref="JsonElement"/>.
        /// </summary>
        /// <param name="element">JSON value to parse.</param>
        /// <param name="context">The parser context.</param>
        /// <returns>null or the parsed <see cref="CsdlExpressionBase"/>.</returns>
        public static CsdlExpressionBase ParseExpression(JsonElement element, JsonParserContext context)
        {
            EdmUtil.CheckArgumentNull(context, nameof(context));

            CsdlLocation location = context.Location();

            switch (element.ValueKind)
            {
            case JsonValueKind.True:
                return(new CsdlConstantExpression(EdmValueKind.Boolean, "true", location));

            case JsonValueKind.False:
                return(new CsdlConstantExpression(EdmValueKind.Boolean, "false", location));

            case JsonValueKind.String:
                // we can't distiguish "Guid, DateTimeOffset, ..." from String at here.
                // So, let's create string for all of string values.
                return(new CsdlConstantExpression(EdmValueKind.String, element.GetString(), location));

            case JsonValueKind.Null:
                return(new CsdlConstantExpression(EdmValueKind.Null, null, location));

            case JsonValueKind.Number:
                return(ParseNumberExpression(element, context));

            case JsonValueKind.Object:
                return(ParseObjectExpression(element, context));

            case JsonValueKind.Array:
                IList <CsdlExpressionBase> elements = element.ParseAsArray(context, (e, c) => ParseExpression(e, c));
                return(new CsdlCollectionExpression(null, elements, location));

            case JsonValueKind.Undefined:
            default:
                context.ReportError(EdmErrorCode.UnknownElementValueKind, Strings.CsdlJsonParser_UnknownJsonElementValueKind(element.ValueKind, context.Path));
                return(null);
            }
        }
コード例 #8
0
        /// <summary>
        /// Parse the <see cref="JsonElement"/> to a <see cref="IEdmInclude"/>.
        /// </summary>
        /// <param name="element">The input JSON element.</param>
        /// <param name="context">The parser context.</param>
        /// <returns>null or parsed <see cref="IEdmInclude"/>.</returns>
        internal static IEdmInclude ParseInclude(JsonElement element, JsonParserContext context)
        {
            // Each item in $Include is an object.
            if (!element.ValidateValueKind(JsonValueKind.Object, context))
            {
                return(null);
            }

            string includeNamespace = null;
            string includeAlias     = null;

            element.ParseAsObject(context, (propertyName, propertyValue) =>
            {
                // Array items are objects that MUST contain the member $Namespace and MAY contain the member $Alias.
                switch (propertyName)
                {
                case "$Alias":
                    // The value of $Alias is a string containing the alias for the included schema.
                    includeAlias = propertyValue.ParseAsString(context);
                    break;

                case "$Namespace":
                    // The value of $Namespace is a string containing the namespace of the included schema
                    includeNamespace = propertyValue.ParseAsString(context);
                    break;

                default:
                    // The item objects MAY contain annotations.
                    // However, EdmInclude does not supported yet. So skip
                    context.ReportError(EdmErrorCode.UnexpectedElement, Strings.CsdlJsonParser_UnexpectedJsonMember(context.Path, propertyValue.ValueKind));
                    break;
                }
            });

            return(new EdmInclude(includeAlias, includeNamespace));
        }
コード例 #9
0
        /// <summary>
        /// Parse CSDL-JSON doc into CsdlModel, error messages are stored in <see cref="JsonParserContext"/>
        /// </summary>
        /// <param name="jsonReader">The JSON reader.</param>
        /// <param name="context">The parser context.</param>
        /// <returns>Null or parsed <see cref="CsdlModel"/>.</returns>
        internal static CsdlModel ParseCsdlDocument(ref Utf8JsonReader jsonReader, JsonParserContext context)
        {
            Debug.Assert(context != null);

            JsonDocument jsonDocument = GetJsonDocument(ref jsonReader, context);

            if (jsonDocument == null)
            {
                return(null);
            }

            // make sure to dispose the JsonDocument.
            using (jsonDocument)
            {
                JsonElement rootElement = jsonDocument.RootElement;

                // A CSDL JSON document consists of a single JSON object.
                if (!rootElement.ValidateValueKind(JsonValueKind.Object, context))
                {
                    return(null);
                }

                // This document object MUST contain the member $Version.
                Version version = rootElement.ProcessRequiredProperty("$Version", context, ParseVersion);
                if (version == null)
                {
                    return(null);
                }

                CsdlModel csdlModel = new CsdlModel
                {
                    CsdlVersion = version
                };

                IList <IEdmReference> references = null;
                rootElement.ParseAsObject(context, (propertyName, propertyValue) =>
                {
                    switch (propertyName)
                    {
                    case "$Version":
                        // skip, because processed
                        break;

                    case "$EntityContainer":
                        // The value of $EntityContainer is the namespace-qualified name of the entity container of that service.
                        // So far, i don't know how to use it. So skip it.
                        break;

                    case "$Reference":
                        // The document object MAY contain the member $Reference to reference other CSDL documents.
                        references = ParseReferences(propertyValue, context);
                        break;

                    default:
                        // CSDL document also MAY contain members for schemas.
                        // Each schema's value is an object.
                        if (propertyValue.ValueKind == JsonValueKind.Object)
                        {
                            CsdlSchema schema = SchemaJsonParser.ParseCsdlSchema(propertyName, csdlModel.CsdlVersion, propertyValue, context);
                            if (schema != null)
                            {
                                csdlModel.AddSchema(schema);
                                break;
                            }
                        }

                        context.ReportError(EdmErrorCode.UnexpectedElement, Strings.CsdlJsonParser_UnexpectedJsonMember(context.Path, propertyValue.ValueKind));
                        break;
                    }
                });


                if (references != null)
                {
                    csdlModel.AddCurrentModelReferences(references);
                }

                return(csdlModel);
            }
        }