kislyuk / yq

Command-line YAML, XML, TOML processor - jq wrapper for YAML/XML/TOML documents
https://kislyuk.github.io/yq/
Apache License 2.0
2.57k stars 82 forks source link

xq introduces '@' prefix on some json words #139

Closed mlsquires closed 2 years ago

mlsquires commented 2 years ago

I've got an xml file produced by nmap that I want to operate on. When I use xq to produce a json file it changes an attribute name in the XML to have a leading '@'.

Here is the original XML and the produced JSON:

nmap_log.xml:11:

nmap_log.json:36: "@addr": "38:94:ED:C8:19:A3",

Is this expected? Is there something in the XML file that triggers this?

kislyuk commented 2 years ago

Yes, this is part of the convention for converting XML attributes to JSON. https://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html

XML nodes (tags) can have both attributes and nested tags attached to them. The least cumbersome way to differentiate between the two when translating to JSON is to attach the @ sigil to attribute names.

mlsquires commented 2 years ago

Thanks for the prompt reply. Makes sense.

joaociocca commented 1 year ago

<edit>

ok, reading https://github.com/kislyuk/yq/issues/69 I saw someone using single quote outside, double quote inside. '.nmaprun.host.ports.port[].state."@state"' worked here. Sorry for bothering about it!

</edit>


I understand the inclusion of @, but whenever I try to refer to an attribute on the jq query, I get broken pipe errors. For example, nmap's XML file:

{
  "nmaprun": {
    "@scanner": "nmap",
    "@args": "nmap --top-ports=100 -sT -Pn -oA nmap_tcp100 <target>",
    "@start": "1673533616",
    "@startstr": "Thu Jan 12 11:26:56 2023",
    "@version": "7.93",
    "@xmloutputversion": "1.05",
    "scaninfo": {
      "@type": "connect",
      "@protocol": "tcp",
      "@numservices": "100",
      "@services": "7,9,13,21-23,25-26,37,53,79-81,88,106,110-111,113,119,135,139,143-144,179,199,389,427,443-445,465,513-515,543-544,548,554,587,631,646,873,990,993,995,1025-1029,1110,1433,1720,1723,1755,1900,2000-2001,2049,2121,2717,3000,3128,3306,3389,3986,4899,5000,5009,5051,5060,5101,5190,5357,5432,5631,5666,5800,5900,6000-6001,6646,7070,8000,8008-8009,8080-8081,8443,8888,9100,9999-10000,32768,49152-49157"
    },
    "verbose": {
      "@level": "0"
    },
    "debugging": {
      "@level": "0"
    },
    "host": {
      "@starttime": "1673533627",
      "@endtime": "1673533628",
      "status": {
        "@state": "up",
        "@reason": "user-set",
        "@reason_ttl": "0"
      },
      "address": {
        "@addr": "<target_ip>",
        "@addrtype": "ipv4"
      },
      "hostnames": {
        "hostname": {
          "@name": "<target>",
          "@type": "user"
        }
      },
      "ports": {
        "extraports": {
          "@state": "filtered",
          "@count": "86",
          "extrareasons": {
            "@reason": "no-response",
            "@count": "86",
            "@proto": "tcp",
            "@ports": "7,9,13,21-23,25-26,37,53,79,81,88,106,110-111,113,119,135,139,143-144,179,199,389,427,444-445,465,513-515,543-544,548,554,587,631,646,873,990,993,995,1025-1029,1110,1433,1720,1723,1755,1900,2000-2001,2049,2121,2717,3000,3128,3306,3389,3986,4899,5000,5009,5051,5060,5101,5190,5357,5432,5631,5666,5800,5900,6000-6001,6646,7070,8000,8009,8081,9100,9999"
          }
        },
        "port": [
          {
            "@protocol": "tcp",
            "@portid": "80",
            "state": {
              "@state": "open",
              "@reason": "syn-ack",
              "@reason_ttl": "0"
            },
            "service": {
              "@name": "http",
              "@method": "table",
              "@conf": "3"
            }
          }
        ]
      },
      "times": {
        "@srtt": "20054",
        "@rttvar": "1878",
        "@to": "100000"
      }
    },
    "runstats": {
      "finished": {
        "@time": "1673533628",
        "@timestr": "Thu Jan 12 11:27:08 2023",
        "@summary": "Nmap done at Thu Jan 12 11:27:08 2023; 1 IP address (1 host up) scanned in 12.92 seconds",
        "@elapsed": "12.92",
        "@exit": "success"
      },
      "hosts": {
        "@up": "1",
        "@down": "0",
        "@total": "1"
      }
    }
  }
}

One thing I wanted to do was retrieve the ports that are open. I've been dealing with jq for quite a while, so the query would end up something like this: .nmaprun.host.ports.port[] | select(.state.@state=="open") | .@port

Going step by step to check, I get as far as .nmaprun.host.ports.port[].state. Whenever I try to look into @state, I get errors:

$ xq ".nmaprun.host.ports.port[].state.@state" nmap_tcp100.xml
jq: error: syntax error, unexpected $end, expecting QQSTRING_START (Unix shell quoting issues?) at <top-level>, line 1:
.nmaprun.host.ports.port[].state.@state
jq: 1 compile error
xq: Error running jq: BrokenPipeError: [Errno 32] Broken pipe.

How to solve that issue? How do I access the value of an attribute?