URI Template 04 Questions

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

URI Template 04 Questions

Thomas Van Lenten
I've been working on an Objective-C implementation of the 04 draft,
and ran into some questions:

  - How should empty strings be handled when the expression has more
then one variable reference?  ('{x,empty,y}')
  - Section 2.3, paragraph 4 says an variable appearing more then once
should have the same value, what if a different default is listed in
both places?  ('X{foo=val1}Y{foo=val2}Z')
  - How should empty strings within arrays be handled? (list = ( 'a',
'', 'b' ) :: '{list}' or '{?list}')
  - How should empty strings as values in an associative array be
handled? ('keys'  = {'key1': 'val1', 'key2': '', 'key3': 'val3' } ::
'{keys}' or '{?keys}')
  - How should empty strings as keys in an associative array be
handled? ('keys'  = {'key1': 'val1', 'key2': 'val2', '': 'val3' } ::
'{keys}' or '{?keys}')

Following the style on the JSON tests in the Python implementation,
I've created a test file with some test cases for extra/exceptional
behaviors that are in the draft but weren't covered with examples.  I
also have a testcase at the end showing the first of the above
questions.

TVL
--
{
  "No varspec (section 3.3, paragraph 3)" :
  {
    "variables": {
       "var"   : "value"
     },
     "testcases" : [
        ["{}", "{}"],
        ["{,}", "{,}"],
        ["{,,}", "{,,}"]
     ]
  },
  "Missing closing brace (section 3.3 paragraph 4)" :
  {
    "variables": {
       "var"   : "value",
       "hello" : "Hello World!",
       "list"  : [ "val1", "val2", "val3" ],
       "keys"  : {"key1": "val1", "key2": "val2"},
       "x"     : "1024",
       "y"     : "768"
     },
     "testcases" : [
        ["{var", "value"],
        ["{hello", "Hello%20World%21"],
        ["{x,y", "1024,768"],
        ["{var=default", "value"],
        ["{undef=default", "default"],
        ["{list", "val1,val2,val3"],
        ["{list*", "val1,val2,val3"],
        ["{list+", "list.val1,list.val2,list.val3"],
        ["{keys", "key1,val1,key2,val2"],
        ["{keys*", "key1,val1,key2,val2"],
        ["{keys+", "keys.key1,val1,keys.key2,val2"]
     ]
  },
  "varspec of only operator and explodes (section 3.3?)" :
  {
    "variables": {
       "var"   : "value"
     },
     "testcases" : [
        ["{+}", "{+}"],
        ["{;}", "{;}"],
        ["{?}", "{?}"],
        ["{/}", "{/}"],
        ["{.}", "{.}"],
        ["{+,}", "{+,}"],
        ["{;,}", "{;,}"],
        ["{?,}", "{?,}"],
        ["{/,}", "{/,}"],
        ["{.,}", "{.,}"],
        ["{++}", "{++}"],
        ["{;+}", "{;+}"],
        ["{?+}", "{?+}"],
        ["{/+}", "{/+}"],
        ["{.+}", "{.+}"],
        ["{+*}", "{+*}"],
        ["{;*}", "{;*}"],
        ["{?*}", "{?*}"],
        ["{/*}", "{/*}"],
        ["{.*}", "{.*}"]
     ]
  },
  "One good varspec and bad varspecs (section 3.3, paragraph 3?)" :
  {
    "variables": {
       "var"   : "value"
     },
     "testcases" : [
        ["{var,}", "value"],
        ["{,var}", "value"],
        ["{,var,,}", "value"],
        ["{+var,,}", "value"],
        ["{;var,,}", ";var=value"],
        ["{?var,,}", "?var=value"],
        ["{/var,,}", "/value"],
        ["{.var,,}", ".value"],
        ["{+,var,}", "value"],
        ["{;,var,}", ";var=value"],
        ["{?,var,}", "?var=value"],
        ["{/,var,}", "/value"],
        ["{.,var,}", ".value"],
        ["{+,,var}", "value"],
        ["{;,,var}", ";var=value"],
        ["{?,,var}", "?var=value"],
        ["{/,,var}", "/value"],
        ["{.,,var}", ".value"]
     ]
  },
  "Multiple undefined variables (section 3.4)" :
  {
    "variables": {
       "var"   : "value"
     },
     "testcases" : [
        ["{undef1,undef2}", ""],
        ["{+undef1,undef2}", ""],
        ["{;undef1,undef2}", ""],
        ["{?undef1,undef2}", ""],
        ["{/undef1,undef2}", ""],
        ["{.undef1,undef2}", ""]
     ]
  },
  "Default with variable in varspec (just reported like above cases)" :
  {
    "variables": {
       "var"   : "value"
     },
     "testcases" : [
        ["{=foo}", "{=foo}"]
     ]
  },
  "varspec with bad partial (partial gets ignored)" :
  {
    "variables": {
       "var"   : "value"
     },
     "testcases" : [
        ["{var:}", "value"],
        ["{var^}", "value"]
     ]
  },
  "Default of empty string and edge cases with empty strings" :
  {
    "variables": {
       "empty" : "",
       "x"     : "1024",
       "y"     : "768"
     },
     "testcases" : [
        ["{empty}", ""],
        ["{;x,empty,y}", ";x=1024;empty;y=768"],
        ["{?x,empty,y}", "?x=1024&empty&y=768"],
        ["{x,empty,y}", "1024,,768"],
        ["{+x,empty,y}", "1024,,768"],
        ["{/x,empty,y}", "/1024//768"],
        ["{.x,empty,y}", ".1024..768"],
        ["{undef=}", ""],
        ["{;x,undef=,y}", ";x=1024;undef;y=768"],
        ["{?x,undef=,y}", "?x=1024&undef&y=768"],
        ["{x,undef=,y}", "1024,,768"],
        ["{+x,undef=,y}", "1024,,768"],
        ["{/x,undef=,y}", "/1024//768"],
        ["{.x,undef=,y}", ".1024..768"]
     ]
  }
}

Reply | Threaded
Open this post in threaded view
|

Re: URI Template 04 Questions

Thomas Van Lenten
On Tue, Sep 28, 2010 at 8:58 AM, Thomas Van Lenten <[hidden email]> wrote:

> On Tue, Sep 28, 2010 at 5:52 AM, Mike Burrows <[hidden email]> wrote:
>>
>> Hi Thomas,
>>
>> On 27 September 2010 22:00, Thomas Van Lenten <[hidden email]> wrote:
>>>
>>> I've been working on an Objective-C implementation of the 04 draft,
>>> and ran into some questions:
>>>
>>>  - How should empty strings be handled when the expression has more
>>> then one variable reference?  ('{x,empty,y}')
>>
>> I believe that this should expand to '1024,,768', because the empty string
>> is a value like any other.  This particular example isn't tested but it's
>> consistent with other tests.  For example, '{?x,y,empty}' expands to
>> '?x=1024&y=768&empty='.
>>
>>>
>>>  - Section 2.3, paragraph 4 says an variable appearing more then once
>>> should have the same value, what if a different default is listed in
>>> both places?  ('X{foo=val1}Y{foo=val2}Z')
>>
>> Mine expands this to 'Xval1Yval2Z'.  Uncontroversial I hope.
>
> It does sortof conflict with the statement that values should have the
> same value through the whole expression.
>
>>
>>>
>>>  - How should empty strings within arrays be handled? (list = ( 'a',
>>> '', 'b' ) :: '{list}' or '{?list}')
>>>
>>>  - How should empty strings as values in an associative array be
>>> handled? ('keys'  = {'key1': 'val1', 'key2': '', 'key3': 'val3' } ::
>>> '{keys}' or '{?keys}')
>>
>> Just more of the same I think, i.e. empty strings are not a special case.
>
> Right, the fact that empty arrays and associative arrays got special
> treatment was part of why I figured I'd check to make sure they there
> were additional expectations around empty strings within them.
>
>>
>>>  - How should empty strings as keys in an associative array be
>>> handled? ('keys'  = {'key1': 'val1', 'key2': 'val2', '': 'val3' } ::
>>> '{keys}' or '{?keys}')
>>
>> Hadn't thought of that one. Is it valid/useful?  But anyway, mine doesn't
>> treat the empty string key any differently.
>
> I wasn't sure, I was just trying to add more cases to cover all the
> combinations and the results were a little odd, so I figured I'd
> confirm that was intended and that a special case wasn't wanted.

Hit send too quick.  Given:

       "list"  : [ "val1", "", "val3" ],
       "keys1"  : {"key1": "", "key2": "val2"},
       "keys2"  : {"key1": "val1", "": "val2"}

Which are correct?

        "{list}" -> "val1,val3"
or
        "{list}" -> "val1,,val3"

        "{keys1}" -> "key2,val2"
or
        "{keys1}" -> "key1,,key2,val2"

        "{keys2}" -> "key1,val1"
or
        "{keys2}" -> ",val2,key1,val1"

I'd actually coded the first before thinking about it.  But maybe the
second ones are right.

TVL

Reply | Threaded
Open this post in threaded view
|

Re: URI Template 04 Questions

Thomas Van Lenten
On Tue, Sep 28, 2010 at 11:01 AM, Cheney, Austin
<[hidden email]> wrote:
> Thomas,
>
> I am not sure of what your objective is with regard to the JSON
> encapsulation.  Since you are talking about JSON then I will speak
> programmatically from a JavaScript perspective.  If you are able to
> interpret JSON without use of a JavaScript interpreter then please
> ignore this email.

The questions are in reference to the URI Template (draft) spec -
http://tools.ietf.org/html/draft-gregorio-uritemplate-04

TVL

>
>>         "{list}" -> "val1,val3"
>> or
>>         "{list}" -> "val1,,val3"
>>
>>         "{keys1}" -> "key2,val2"
>> or
>>         "{keys1}" -> "key1,,key2,val2"
>>
>>         "{keys2}" -> "key1,val1"
>> or
>>         "{keys2}" -> ",val2,key1,val1"
>
> In the first instance of each of the three examples it appears that
> indexes are collapsed to support only the minimum number of variables
> while the second instance of each of the examples an empty index is
> preserved in the absence of a supplied variable.
>
> The first instances are fine if you know in advance that the indexes are
> collapsed before interpreting the JSON, because then you can perform one
> of two precautions.  The first precaution is to pre append a label to
> the variables so that the receiving logic knows to what each of the
> variables are without regard for their location in the index of the keys
> and list objects.  Some examples of pre appending a label could be:
>
>   val1 = ["val1", val1];
>   val1 = "val1|" + val1;
>
> The second precaution to take to prevent ambiguity when index location
> becomes irrelevant is to perform some sort of associative logic that
> either prevents the inclusion of certain variables under certain
> conditions, but selectivity is only relevant if such logical conditions
> are equally known to any interpreting logic, or builds a parallel object
> of labels and an equal number of indexes.  I have found that parallel
> objects and arrays are the most efficient means of processing large
> objects and arrays in JavaScript.  Here is an example:
>
>   list = {val1, val3};
>   label = {lab1, lab3};
>
> This is the most efficient means of processing because the number of
> indexes are collapsed, and that results in the fewest number of loop
> iterations.  Since a parallel object contains the labels and not the
> object of value you can target each object respectively to find what you
> need by referring to the same identical index.  Please be aware that
> when using parallel objects/arrays each index, as well as nested index,
> must be created in tandem or one must be based entirely off the other.
> All that matters with this scheme is that the indexes are always in
> sync, and if those indexes become mismatched you will be interpreting
> data in error.  I have an example at
> http://prettydiff.com/markup_beauty.js, where the build, cinfo, token,
> and length arrays are all parallel.
>
> It should be noted that for large data sets parallel objects/arrays
> requires a larger addressable space in memory, but I have never seen
> this become a problem.  Most performance increases typically result from
> reduction of function calls and conditions in loops, except in
> TraceMonkey.
>
> The second instance of each of your three examples requires
> significantly less logic to interpret the objects and a little less
> logic to build out those objects.  This method may be faster for you to
> write, but it will be less efficient to process against large indexes.
> Since there is less logic to write that means there is less data to
> transmit across the wire if the objects are not created prior to
> transport.  When writing JavaScript I have found it is better for the
> user experience to send slightly larger amounts of logic if that
> increase in logic results in vastly superior performance.
>
> If this does not go across the wire, such as server side JavaScript
> interpretation, then you have to be entirely aware of what executes the
> JavaScript.  JavaScript interpretation is by no means fast.  It is the
> slowest language I have ever seen.  Keep in mind that PHP and Perl are
> also interpreted languages, but they are radically faster than
> JavaScript even after the advances in modern interpretation engines such
> as Presto and V8.  If external factors are trigging the execution of
> JavaScript interpretation then by all means write the code to be as
> efficient to process as possible, otherwise you will spend more money
> then you need to on maintaining servers.
>
> Thanks,
>
> Austin Cheney, Travelocity User Experience
> CISSP TS/SCI
>

Reply | Threaded
Open this post in threaded view
|

Re: URI Template 04 Questions

Thomas Van Lenten
In reply to this post by Thomas Van Lenten
On Tue, Sep 28, 2010 at 9:20 AM, Thomas Van Lenten <[hidden email]> wrote:

> On Tue, Sep 28, 2010 at 8:58 AM, Thomas Van Lenten <[hidden email]> wrote:
>> On Tue, Sep 28, 2010 at 5:52 AM, Mike Burrows <[hidden email]> wrote:
>>>
>>> Hi Thomas,
>>>
>>> On 27 September 2010 22:00, Thomas Van Lenten <[hidden email]> wrote:
>>>>
>>>> I've been working on an Objective-C implementation of the 04 draft,
>>>> and ran into some questions:
>>>>
>>>>  - How should empty strings be handled when the expression has more
>>>> then one variable reference?  ('{x,empty,y}')
>>>
>>> I believe that this should expand to '1024,,768', because the empty string
>>> is a value like any other.  This particular example isn't tested but it's
>>> consistent with other tests.  For example, '{?x,y,empty}' expands to
>>> '?x=1024&y=768&empty='.
>>>
>>>>
>>>>  - Section 2.3, paragraph 4 says an variable appearing more then once
>>>> should have the same value, what if a different default is listed in
>>>> both places?  ('X{foo=val1}Y{foo=val2}Z')
>>>
>>> Mine expands this to 'Xval1Yval2Z'.  Uncontroversial I hope.
>>
>> It does sortof conflict with the statement that values should have the
>> same value through the whole expression.
>>
>>>
>>>>
>>>>  - How should empty strings within arrays be handled? (list = ( 'a',
>>>> '', 'b' ) :: '{list}' or '{?list}')
>>>>
>>>>  - How should empty strings as values in an associative array be
>>>> handled? ('keys'  = {'key1': 'val1', 'key2': '', 'key3': 'val3' } ::
>>>> '{keys}' or '{?keys}')
>>>
>>> Just more of the same I think, i.e. empty strings are not a special case.
>>
>> Right, the fact that empty arrays and associative arrays got special
>> treatment was part of why I figured I'd check to make sure they there
>> were additional expectations around empty strings within them.
>>
>>>
>>>>  - How should empty strings as keys in an associative array be
>>>> handled? ('keys'  = {'key1': 'val1', 'key2': 'val2', '': 'val3' } ::
>>>> '{keys}' or '{?keys}')
>>>
>>> Hadn't thought of that one. Is it valid/useful?  But anyway, mine doesn't
>>> treat the empty string key any differently.
>>
>> I wasn't sure, I was just trying to add more cases to cover all the
>> combinations and the results were a little odd, so I figured I'd
>> confirm that was intended and that a special case wasn't wanted.
>
> Hit send too quick.  Given:
>
>       "list"  : [ "val1", "", "val3" ],
>       "keys1"  : {"key1": "", "key2": "val2"},
>       "keys2"  : {"key1": "val1", "": "val2"}
>
> Which are correct?
>
>        "{list}" -> "val1,val3"
> or
>        "{list}" -> "val1,,val3"
>
>        "{keys1}" -> "key2,val2"
> or
>        "{keys1}" -> "key1,,key2,val2"
>
>        "{keys2}" -> "key1,val1"
> or
>        "{keys2}" -> ",val2,key1,val1"
>
> I'd actually coded the first before thinking about it.  But maybe the
> second ones are right.

After a side thread with Mike Burrows, I'm thinking the first are
probably the right values.  Here's another chunk for testing
implementations.  The most interesting cases are probably:

  '{;keysA}' -> ';key1,key2,val2'
  '{;keysA*}' -> ';key1;key2=val2'
  '{;keysA+}' -> ';keysA.key1;keysA.key2=val2'
  '{?keysA}' -> '?keysA=key1,key2,val2'
  '{?keysA*}' -> '?key1&key2=val2'
  '{?keysA+}' -> '?keysA.key1&keysA.key2=val2'

TVL
--
  "Two defaults for one variable" :
  {
    "variables": {
       "y"     : "768"
     },
     "testcases" : [
        ["1{undef=a}2{undef=b}3", "1a2b3"]
        ["0{undef}1{undef=a}2{undef}3{undef=b}4{undef}5", "01a2a3b4b5"]
     ]
  },
  "Empty strings within arrays and associative arrays" :
  {
    "variables": {
       "list"  : [ "val1", "", "val3" ],
       "keysA"  : {"key1": "", "key2": "val2"},
       "keysB"  : {"key1": "val1", "": "val2"}
     },
     "testcases" : [
        ["{list}", "val1,,val3"],
        ["{list*}", "val1,,val3"],
        ["{list+}", "list.val1,list.,list.val3"],
        ["{keysA}", "key1,,key2,val2"],
        ["{keysA*}", "key1,,key2,val2"],
        ["{keysA+}", "keysA.key1,,keysA.key2,val2"],
        ["{keysB}", ",val2,key1,val1"],
        ["{keysB*}", ",val2,key1,val1"],
        ["{keysB+}", "keysB.,val2,keysB.key1,val1"],
        ["{+list}", "val1,,val3"],
        ["{+list*}", "val1,,val3"],
        ["{+list+}", "list.val1,list.,list.val3"],
        ["{+keysA}", "key1,,key2,val2"],
        ["{+keysA*}", "key1,,key2,val2"],
        ["{+keysA+}", "keysA.key1,,keysA.key2,val2"],
        ["{+keysB}", ",val2,key1,val1"],
        ["{+keysB*}", ",val2,key1,val1"],
        ["{+keysB+}", "keysB.,val2,keysB.key1,val1"],
        ["{;list}", ";val1,,val3"],
        ["{;list*}", ";val1;;val3"],
        ["{;list+}", ";list=val1;list=;list=val3"],
        ["{;keysA}", ";key1,key2,val2"],
        ["{;keysA*}", ";key1;key2=val2"],
        ["{;keysA+}", ";keysA.key1;keysA.key2=val2"],
        ["{;keysB}", ";,val2,key1,val1"],
        ["{;keysB*}", ";=val2;key1=val1"],
        ["{;keysB+}", ";keysB.=val2;keysB.key1=val1"],
        ["{?list}", "?list=val1,,val3"],
        ["{?list*}", "?val1&&val3"],
        ["{?list+}", "?list=val1&list=&list=val3"],
        ["{?keysA}", "?keysA=key1,key2,val2"],
        ["{?keysA*}", "?key1&key2=val2"],
        ["{?keysA+}", "?keysA.key1&keysA.key2=val2"],
        ["{?keysB}", "?keysB=,val2,key1,val1"],
        ["{?keysB*}", "?=val2&key1=val1"],
        ["{?keysB+}", "?keysB.=val2&keysB.key1=val1"],
        ["{/list}", "/val1,,val3"],
        ["{/list*}", "/val1//val3"],
        ["{/list+}", "/list.val1/list./list.val3"],
        ["{/keysA}", "/key1,,key2,val2"],
        ["{/keysA*}", "/key1//key2/val2"],
        ["{/keysA+}", "/keysA.key1//keysA.key2/val2"],
        ["{/keysB}", "/,val2,key1,val1"],
        ["{/keysB*}", "//val2/key1/val1"],
        ["{/keysB+}", "/keysB./val2/keysB.key1/val1"],
        ["X{.list}", "X.val1,,val3"],
        ["X{.list*}", "X.val1..val3"],
        ["X{.list+}", "X.list.val1.list..list.val3"],
        ["X{.keysA}", "X.key1,,key2,val2"],
        ["X{.keysA*}", "X.key1..key2.val2"],
        ["X{.keysA+}", "X.keysA.key1..keysA.key2.val2"],
        ["X{.keysB}", "X.,val2,key1,val1"],
        ["X{.keysB*}", "X..val2.key1.val1"],
        ["X{.keysB+}", "X.keysB..val2.keysB.key1.val1"]
     ]
  }