# How can I highlight JSON string values but not attributes?

example
{
"name" : "alan",
"alias" : "nala"
}


If I use

morecomment=[s][\color{red}]{"}{"},


How can I highlight JSON string values (on the right side) but not the attributes (left side)?

A MWE is really needed here, so what follows is a bit of a shot in the dark...

Edit: now you can specify a distinct style for numerical JSON values.

\documentclass{article}

%\usepackage[T1]{fontenc}
%\usepackage[scaled=0.85]{beramono}
\usepackage{xcolor}
\usepackage{listings}

\newcommand\JSONnumbervaluestyle{\color{blue}}
\newcommand\JSONstringvaluestyle{\color{red}}

% switch used as state variable
\newif\ifcolonfoundonthisline

\makeatletter

\lstdefinestyle{json}
{
showstringspaces    = false,
keywords            = {false,true},
alsoletter          = 0123456789.,
morestring          = [s]{"}{"},
stringstyle         = \ifcolonfoundonthisline\JSONstringvaluestyle\fi,
MoreSelectCharTable =%
\lst@DefSaveDef{:}\colon@json{\processColon@json},
basicstyle          = \ttfamily,
keywordstyle        = \ttfamily\bfseries,
}

% flip the switch if a colon is found in Pmode
\newcommand\processColon@json{%
\colon@json%
\ifnum\lst@mode=\lst@Pmode%
\global\colonfoundonthislinetrue%
\fi
}

\ifcolonfoundonthisline%
\ifnum\lst@mode=\lst@Pmode%
\def\lst@thestyle{\JSONnumbervaluestyle}%
\fi
\fi
%override by keyword style if a keyword is detected!
\lsthk@DetectKeywords%
}

% reset the switch at the end of line
{\global\colonfoundonthislinefalse}

\makeatother

\begin{document}

\section{A simple example}
\begin{lstlisting}[style=json]
example
{
"name" : "alan",
"alias" : "nala",
}
\end{lstlisting}

\section{A more complicated example}
\begin{lstlisting}[style=json]
{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 25,
"height_cm": 167.6,
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
]
}
\end{lstlisting}

\end{document}

• how about set another style number w/o quote? – keepscoding Aug 9 '14 at 15:28
• @user3782003 See my edit. In the future, please post a minimal working example (MWE) in your question. – jub0bs Aug 9 '14 at 16:04
• What about having escaped quotes on the right side? I have got this one: "content": "<Dat url=\"yawRate\"\\n ><Abs name=\"yawRate\" val=\"-.01\"/>\\n</Dat>" and want the whole string to be in one color as it is one value. Can you help? – tellob Jun 18 '15 at 6:52
• Did with an additional morestring = [s]{"<}{>"} – tellob Jun 18 '15 at 7:08

Building on @jub0bs's fantastic answer, I was able to devise the following language definition:

\documentclass{article}
%\usepackage[T1]{fontenc}
\usepackage{xcolor}
\usepackage{listings}

\newcommand\jsonkey{\color{purple}}
\newcommand\jsonvalue{\color{cyan}}
\newcommand\jsonnumber{\color{orange}}

% switch used as state variable
\makeatletter
\newif\ifisvalue@json

\lstdefinelanguage{json}{
tabsize             = 4,
showstringspaces    = false,
keywords            = {false,true},
alsoletter          = 0123456789.,
morestring          = [s]{"}{"},
stringstyle         = \jsonkey\ifisvalue@json\jsonvalue\fi,
MoreSelectCharTable = \lst@DefSaveDef{:}\colon@json{\enterMode@json},
MoreSelectCharTable = \lst@DefSaveDef{,}\comma@json{\exitMode@json{\comma@json}},
MoreSelectCharTable = \lst@DefSaveDef{\{}\bracket@json{\exitMode@json{\bracket@json}},
basicstyle          = \ttfamily
}

% enter "value" mode after encountering a colon
\newcommand\enterMode@json{%
\colon@json%
\ifnum\lst@mode=\lst@Pmode%
\global\isvalue@jsontrue%
\fi
}

% leave "value" mode: either we hit a comma, or the value is a nested object
\newcommand\exitMode@json[1]{#1\global\isvalue@jsonfalse}

\ifisvalue@json%
\ifnum\lst@mode=\lst@Pmode%
\def\lst@thestyle{\jsonnumber}%
\fi
\fi
%override by keyword style if a keyword is detected!
\lsthk@DetectKeywords%
}

\makeatother

\begin{document}

\section{A complex example}
\begin{lstlisting}[language=json]
{
"hello": "world",
"traits": {"rotated": false, "x": 100, "y": 200},
"name":
"test"
}
\end{lstlisting}

\end{document}


The main fix introduced here is that whitespace is ignored --- multiple key/value pairs can exist on the same line and get highlighted correctly, while there can also be multiple lines between the key and the value and highlighting is also retained in this case:

Another useful improvement is that this version also supports highlighting of the key, rather than just the value. While this was not required for the initial question, it is a common use case, and since this question is at the top of searches on how highlight JSON in this manner, I feel that it is useful to include.