joshbuddy/jsonpath

Can't parse a specific pattern

Closed this issue · 9 comments

@Skarlso not sure how to explain this issue, so just going to provide example JSON, Path, expected output and actual output. Let me know if you need further information.

This works on jsonpath.com (but returns [] with JsonPath.on.

JSON

{
  "ports": {
    "extraports": {
      "count": "996",
      "state": "filtered",
      "extrareasons": {
        "count": "996",
        "reason": "no-responses"
      }
    },
    "port": [
      {
        "portid": "80",
        "protocol": "tcp",
        "service": {
          "conf": "3",
          "method": "table",
          "name": "http"
        },
        "state": {
          "reason": "syn-ack",
          "reason_ttl": "44",
          "state": "open"
        }
      },
      {
        "portid": "443",
        "protocol": "tcp",
        "service": {
          "conf": "3",
          "method": "table",
          "name": "https"
        },
        "state": {
          "reason": "syn-ack",
          "reason_ttl": "44",
          "state": "open"
        }
      },
      {
        "portid": "2222",
        "protocol": "tcp",
        "service": {
          "conf": "3",
          "method": "table",
          "name": "EtherNetIP-1"
        },
        "state": {
          "reason": "syn-ack",
          "reason_ttl": "45",
          "state": "open"
        }
      },
      {
        "portid": "3128",
        "protocol": "tcp",
        "service": {
          "conf": "3",
          "method": "table",
          "name": "squid-http"
        },
        "state": {
          "reason": "syn-ack",
          "reason_ttl": "44",
          "state": "open"
        }
      }
    ]
  }
}

JsonPath

Version 1

$..[?(/http/.test(@.name))]

Expected output

[
  {
    "conf": "3",
    "method": "table",
    "name": "http"
  },
  {
    "conf": "3",
    "method": "table",
    "name": "https"
  },
  {
    "conf": "3",
    "method": "table",
    "name": "squid-http"
  }
]

Version 2

$.ports.port[?(/http/.test(@.service.name))]

Expected output

[
  {
    "portid": "80",
    "protocol": "tcp",
    "service": {
      "conf": "3",
      "method": "table",
      "name": "http"
    },
    "state": {
      "reason": "syn-ack",
      "reason_ttl": "44",
      "state": "open"
    }
  },
  {
    "portid": "443",
    "protocol": "tcp",
    "service": {
      "conf": "3",
      "method": "table",
      "name": "https"
    },
    "state": {
      "reason": "syn-ack",
      "reason_ttl": "44",
      "state": "open"
    }
  },
  {
    "portid": "3128",
    "protocol": "tcp",
    "service": {
      "conf": "3",
      "method": "table",
      "name": "squid-http"
    },
    "state": {
      "reason": "syn-ack",
      "reason_ttl": "44",
      "state": "open"
    }
  }
]

Both return

[]

@NDuggan So sorry, was bogged down with a ton of stuff! This is next on my todo list now though. :)

What... even is that? :D

Oh it's a regex match against an element. Or at least something like a "%http%" in SQL and the likes. Hmmmmmm.....

The parsing kind of completely falls apart on this one. :/ Uh.

Alright, so I might be able to handle this gracefully, I think. Your pattern in that case would be something like /http/.match(@whatever. I'm using match to conform to ruby's regex match.

I wonder if this syntax is a standard that should be adopted? there is no standard reference other than the original https://goessner.net/articles/JsonPath/ and even there makes no mention of filters supporting regex

Looking at the Java implementation to support regex filter is also different: https://github.com/json-path/JsonPath

Yah, that's why I was reluctant to do it. It sort of messes things up a bit. :/ But I might implement it at one point anyways. :)

@khairihafsham It just dawned on my that I'm supporting regex in a query.

You could try ?(@name =~ /http[s]?/) or something like that.

@khairihafsham Yep. This actually works:

  def test_regex_2
    json = '
    {
      "ports": {
        "extraports": {
          "count": "996",
          "state": "filtered",
          "extrareasons": {
            "count": "996",
            "reason": "no-responses"
          }
        },
        "port": [
          {
            "portid": "80",
            "protocol": "tcp",
            "service": {
              "conf": "3",
              "method": "table",
              "name": "http"
            },
            "state": {
              "reason": "syn-ack",
              "reason_ttl": "44",
              "state": "open"
            }
          },
          {
            "portid": "443",
            "protocol": "tcp",
            "service": {
              "conf": "3",
              "method": "table",
              "name": "https"
            },
            "state": {
              "reason": "syn-ack",
              "reason_ttl": "44",
              "state": "open"
            }
          },
          {
            "portid": "2222",
            "protocol": "tcp",
            "service": {
              "conf": "3",
              "method": "table",
              "name": "EtherNetIP-1"
            },
            "state": {
              "reason": "syn-ack",
              "reason_ttl": "45",
              "state": "open"
            }
          },
          {
            "portid": "3128",
            "protocol": "tcp",
            "service": {
              "conf": "3",
              "method": "table",
              "name": "squid-http"
            },
            "state": {
              "reason": "syn-ack",
              "reason_ttl": "44",
              "state": "open"
            }
          }
        ]
      }
    }
    '.to_json
    assert_equal [{"conf"=>"3", "method"=>"table", "name"=>"http"}, {"conf"=>"3", "method"=>"table", "name"=>"https"}, {"conf"=>"3", "method"=>"table", "name"=>"squid-http"}], JsonPath.on(json, "$..[?(@.name =~ /http[s]?/)]")
  end