xml data lost in JSON conversion - asp.net

I am getting the following result from converting xml to JSON, using more than one conversion library. As you can see, the property name attributes are lost, as are the Item name attributes. Why?
Does anyone have recommendations on how I might change my XML to make it more conversion friendly?
<Asset name="xyz">
<Property name="p1">Value 1</Property>
<Property name="p2">Value 2</Property>
<TimeSeries name="TimeSeries Name 1">
<Item name="30 Apr 2009">97.47219</Item>
<Item name="01 May 2009">97.16496</Item>
<Item name="05 May 2009">97.34606</Item>
</TimeSeries>
</Asset>
Returns:
{
"Asset": {
"#attributes": {
"name": "xyz"
},
"Property": ["Value 1", "Value 2"],
"TimeSeries": {
"#attributes": {
"name": "TimeSeries Name 1"
},
"Item": ["97.47219", "97.16496", "97.34606"]
}
}
}
I have tried the following, but both the XML and JSON are a lot more verbose:
<Asset name="xyz">
<Property><name>p1</name><value>Value 1</value></Property>
<Property><name>p2</name><value>Value 2</value></Property>
<TimeSeries name="TimeSeries Name 1">
<Item><date>30 Apr 2009</date><value>97.47219</value></Item>
<Item><date>01 May 2009</date><value>97.16496</value></Item>
<Item><date>05 May 2009</date><value>97.34606</value></Item>
</TimeSeries>
</Asset>
resulting in...
{
"Asset": {
"#attributes": {
"name": "xyz"
},
"Property": [{
"name": "p1",
"value": "Value 1"
}, {
"name": "p2",
"value": "Value 2"
}],
"TimeSeries": {
"#attributes": {
"name": "TimeSeries Name 1"
},
"Item": [{
"date": "30 Apr 2009",
"value": "97.47219"
},
{
"date": "01 May 2009",
"value": "97.16496"
}, {
"date": "05 May 2009",
"value": "97.34606"
}
]
}
}
}

Probably you should never use attributes in the source XML file if you use this conversion tool.
You main problem I see is that you don't design the data yourself and try usage of a strange tool. If you use ASP.NET on the server side, it is much better to design your C# classes, initialize an instance of the classes with any test data and use JSON serialization like DataContractJsonSerializer or use a simple Web Service. Look at Can I return JSON from an .asmx Web Service if the ContentType is not JSON? or How do I build a JSON object to send to an AJAX WebService? as examples.

Related

OData Dynamic Model Self-Referencing Navigation Property "Max Level" Expansion

I am developing an OData Web API with dynamic models (no CLR-based types of any kind). Note that this concept is heavily predicated upon the ODataDynamicModel found on GitHub (https://github.com/OData/AspNetCoreOData/tree/main/sample/ODataDynamicModel). Contained within the dynamic model is a self-referencing navigation property named "Items". The OData CSDL is shown below.
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="ns">
<EntityType Name="Item">
<Key>
<PropertyRef Name="ID"/>
</Key>
<Property Name="ID" Type="Edm.Int32"/>
<Property Name="Name" Type="Edm.String"/>
<NavigationProperty Name="Detail" Type="ns.Detail" ContainsTarget="true"/>
**<NavigationProperty Name="Items" Type="Collection(ns.Item)" ContainsTarget="true"/>**
</EntityType>
<EntityType Name="Detail">
<Key>
<PropertyRef Name="ID"/>
</Key>
<Property Name="ID" Type="Edm.Int32"/>
<Property Name="Description" Type="Edm.String"/>
</EntityType>
<EntityContainer Name="Default">
<EntitySet Name="Items" EntityType="ns.Item"/>
<EntitySet Name="Details" EntityType="ns.Detail"/>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
For testing purposes, my API is serving up a static data source so as to eliminate unnecessary complexities such as ORM, etc. I am able to query the data source via OData in its entirety when providing an explicit, fully-defined query string as shown below.
[GET]
http://localhost:4527/odata/ns/Items?$expand=Detail,Items($expand=Detail,Items($expand=Detail,Items($expand=Detail,Items($expand=Detail,Items($expand=Detail,Items)))))
Response:
{
"#odata.context": "http://localhost:4527/odata/ns/$metadata#Items(Detail(),Items(Detail(),Items(Detail(),Items(Detail(),Items(Detail(),Items(Detail(),Items()))))))",
"value": [
{
"ID": 1,
"Name": "Item 1",
"Detail": {
"ID": 1,
"Description": "Detail 1"
},
"Items": [
{
"ID": 2,
"Name": "Item 2",
"Detail": {
"ID": 2,
"Description": "Detail 2"
},
"Items": [
{
"ID": 3,
"Name": "Item 3",
"Detail": {
"ID": 3,
"Description": "Detail 3"
},
"Items": [
{
"ID": 4,
"Name": "Item 4",
"Detail": {
"ID": 4,
"Description": "Detail 4"
},
"Items": []
}
]
}
]
}
]
}
]
}
Retrieval of the same response payload fails when attempting to take advantage of OData's "levels" capabilities as shown below.
[GET]
http://localhost:4527/odata/ns/Items?$expand=Items($levels=10;$expand=Detail),Detail
Response:
{
"#odata.context": "http://localhost:4527/odata/ns/$metadata#Items(Items(Detail()),Detail())",
"value": [
{
"ID": 1,
"Name": "Item 1",
"Items": [
{
"ID": 2,
"Name": "Item 2",
"Detail": {
"ID": 2,
"Description": "Detail 2"
}
}
],
"Detail": {
"ID": 1,
"Description": "Detail 1"
}
}
]
}
I have tried many things without success and am currently stumped to say the least. I posted to the discussion board on Git (https://github.com/OData/AspNetCoreOData/discussions/789) but haven't received a response, which is to be expected this time of year. Attached to that discussion is a small zip file containing a working solution demonstrating the current approach. I'm hopeful that someone out there better versed in the ways of OData can point me in the proper direction. Any and all suggestions are appreciated!

Is there a way to support JSON schema references in Paw?

Paw has good tools for documenting simple APIs, but now I need to do something more complicated and I would like to use JSON Schema references.
For example, like the following snippet from the Swagger 2.0 examples, where the definitions are presented later in the document:
"post": {
"description": "Creates a new pet in the store. Duplicates are allowed",
"operationId": "addPet",
"parameters": [
{
"name": "pet",
"in": "body",
"description": "Pet to add to the store",
"required": true,
"schema": {
"$ref": "#/definitions/NewPet"
}
}
],
...
Is there a way to to this in Paw?

JSON API format in API-Platform

First of all I want to implement JSON API.
I follow tutorial on api platform and just like in example create entities and response is like
{
"links": {
"self": "/api/books"
},
"meta": {
"totalItems": 1,
"itemsPerPage": 30,
"currentPage": 1
},
"data": [
{
"id": "/api/books/1",
"type": "Book",
"attributes": {
"isbn": "9781782164104",
"title": "Persistence in PHP with the Doctrine ORM",
"description": "This book is designed for PHP developers and architects who want to modernize their skills through better understanding of Persistence and ORM.",
"author": "Kévin Dunglas",
"publicationDate": "2013-12-01T00:00:00+01:00",
"_id": 1
},
"relationships": {
"reviews": {
"data": [
{
"type": "Review",
"id": "/api/reviews/1"
}
]
}
}
}
]
}
My api_platform.yaml config
api_platform:
mapping:
paths: ['%kernel.project_dir%/src/Entity']
formats:
jsonapi:
mime_types: ['application/vnd.api+json']
So i have problem with id filed in data. I get id fields in format api/entityName/id but I just want to get number(string), just like in JSON API. So is there some configuration that i miss or is any way to achieve that
It was discussed here.
You need to use Normalizer or create custom getter.
All you need is to send
Accept: application/json
on request header.

How to filter by nested attributes in JSONAPI?

Assuming we have the following data structure
"data": [
{
"type": "node--press",
"id": "f04eab99-9174-4d00-bbbe-cdf45056660e",
"attributes": {
"nid": 130,
"uuid": "f04eab99-9174-4d00-bbbe-cdf45056660e",
"title": "TITLE OF NODE",
"revision_translation_affected": true,
"path": {
"alias": "/press/title-of-node",
"pid": 428,
"langcode": "es"
}
...
}
The data returned is compliant with JSON API standards, and I have no problem retrieving and processing it, except for the fact that I need to be able to filter the nodes returned by the path pid.
How can I filter my data by path.pid?
I have tried:
- node-press?filter[path][pid]=428
- node-press?filter[path][pid][value]=428
to no avail
It's not well defined in the filters section of the specification but other parameters such as include describe accessing nested keys with dot-notation. You could try ?filter[path.pid]=428 and parse the filter that way.
"field_country": {
"data": {
"type": "taxonomy_term--country",
"id": "818f11ab-dd9d-406b-b1ca-f79491eedd73"
}
}
Above structure can be filtered by ?filter[field_country.id]=818f11ab-dd9d-406b-b1ca-f79491eedd73

asp.net Action to receive a complex json with a complex collection

This is a tough one: Basically I want to map a complex JSON object with a collection consisting of different but similar complex types into a C# model.
This is a default JSON my ASP.NET Web API will receive:
{
"Id": "000111222333",
"Move": {
"Address2": {
"City": "CityName",
"Street": "StreetName",
"PostalCode": "4444",
"HouseNumber": "4",
"Country": "NLD",
"IsInhabited": "true"
},
"Contracts": {
"ElectricityContract": {
"ContractId": "000000031",
"ContractNumber": "00000011",
"EANCode": "53123123123123",
"StartDate": "2000-01-20",
"EndDate": "2017-06-06",
"IsBuildingComplex": "false",
"ForceSingleTariff": "false"
},
"CableContract": {
"ContractId": "456454546353",
"ContractNumber": "12312312313",
"StartDate": "2000-01-20",
"EndDate": "2017-01-23"
}
}
}
}
My problem here is that I can't seem to receive the different kinds of Contracts as a single collection.
I've tried to map the "Contracts" sequence to an ArrayList but its always 'null'.
I've tried to map it to ICollection/IEnumerable/List< IContract> where all contracts are a type of IContract. But this doesn't work as well.
I've started to manually map from the JSON string, but I hope there's a better way to do this? All help appreciated.
To get a Contracts collection inside this object you need to change your JSON to this one
{
...
"Contracts": [
{
"ContractId": "000000031",
"Type": "ElectricityContract",
"ContractNumber": "00000011",
"EANCode": "53123123123123",
"StartDate": "2000-01-20",
"EndDate": "2017-06-06",
"IsBuildingComplex": "false",
"ForceSingleTariff": "false"
},
{
"ContractId": "456454546353",
"Type" : "CableContract",
"ContractNumber": "12312312313",
"StartDate": "2000-01-20",
"EndDate": "2017-01-23"
}
]
}
So, Contracts will be a JSON collection not an object and you can map it by using custom binding to ICollection/IEnumerable/List<IContract>. This binding should create different IContract implementation according to Type property.
How to do this - take a look at this post.

Resources