---
title: "Parsing functions"
description: "TapHome script parsing: cut a value between two patterns with PARSETEXT, read JSON with PARSEJSON and XML with PARSEXML, and handle missing values."
url: "https://taphome.com/en/docs/script/parsing-functions/"
language: en
lastmod: 2026-11-06
generator: hugo
ai:
  topics: ["parsing","json","xml","text-extraction","scripting-language"]
  questions: ["How to parse JSON data in TapHome script?","How do I extract a value from XML in TapHome?","How to parse text between two patterns with PARSETEXT?","How do I read a nested JSON field with a JSON path?","How do I handle missing elements when parsing JSON?","How do I parse XML that contains namespaces?","Why does PARSETEXT stop the script with \"Specified argument was out of the range of valid values\"?","How do I loop over a JSON array in a TapHome script?"]
---

# Parsing functions

TapHome script parsing functions — PARSETEXT for text between patterns, PARSEJSON with JSONPath and PARSEXML with XPath — for reading values from device responses.

Last updated: 2026-11-06

Parsing functions read values from text that a device returns — typically the response of an HTTP request or a received message in a [Packet parser](https://taphome.com/en/docs/script/packet-parser/) script. They accept a string, a byte collection (`collection<uint8>`) or a blob, work in every script and need Core 2022.2 or newer.

## PARSETEXT

`PARSETEXT` returns the part of a text that follows a left pattern and ends before a right pattern; when that part is a number, a number is returned.

```text
PARSETEXT(source, leftPattern)
PARSETEXT(source, leftPattern, rightPattern)
```

| Name | Type | Description |
|---|---|---|
| `source` | string, `collection<uint8>` or blob | Text to search. Bytes are read as `iso-8859-1`. |
| `leftPattern` | string | Text before the value. Several parts separated by `...` are found one after another. |
| `rightPattern` | string, optional | Text after the value. Without it the value ends at the first character that is not a letter, a digit or `.` (a leading `+` or `-` is kept). |

**Returns** — a number when the found text reads as a number (with a decimal point), otherwise the text with spaces trimmed. `Null` when the left pattern is not found.

> [!WARNING]
> When the left pattern is found but the right pattern is not, the script stops with the error *Specified argument was out of the range of valid values.* — it does not return `Null`. When the right pattern may be missing, check it with `INDEXOF` first (verified on Core 2026.1).

**Example**

```taphome
# text between two patterns
PARSETEXT("Lorem ipsum dolor sit amet", "ipsum", "amet");
# Result: "dolor sit"
PARSETEXT("<temp>12.2</temp>", "<temp>", "</temp>");
# Result: 12.2
# no right pattern: value ends at the first other character
PARSETEXT("<temp>12.2</temp>", "<temp>");
# Result: 12.2
PARSETEXT("status:ok,error:none", "status:");
# Result: "ok"
# several left parts, found one after another
PARSETEXT("Lorem ipsum dolor sit amet", "ipsum...sit");
# Result: "amet"
PARSETEXT("Lorem ipsum dolor sit amet consectetur adipiscing", "ipsum...sit", "adipiscing");
# Result: "amet consectetur"
# left pattern not found
PARSETEXT("a=1", "b=");
# Result: Null
```

**Example — right pattern that may be missing**

```taphome
# position of the left pattern
VAR start := INDEXOF(text, "temp=");
# leave when the right pattern is missing
IF start < 0 OR INDEXOF(COPY(text, start), ";") < 0
    RETURN(NaN);
END
# read the value between the patterns
PARSETEXT(text, "temp=", ";");
```

**See also** — [INDEXOF](https://taphome.com/en/docs/script/text-string-and-byte-array/#indexof), [COPY](https://taphome.com/en/docs/script/text-string-and-byte-array/#copy).

## PARSEJSON

`PARSEJSON` reads a value from JSON with a JSONPath expression; with `TRUE` as the third argument it returns `Null` instead of stopping the script when the path is not found.

```text
PARSEJSON(json, path)
PARSEJSON(json, path, ignoreError)
```

| Name | Type | Description |
|---|---|---|
| `json` | string, `collection<uint8>` or blob | JSON text. |
| `path` | string | JSONPath. The leading `$.` is optional. |
| `ignoreError` | bool, optional | `TRUE` (or `1`): return `Null` when the path is not found, the JSON is invalid or `json` is `Null`. Default `FALSE`. |

**Returns** — the value at the path: a string, a number or a bool. Several matches are returned as a collection. An object or an array is returned as its JSON text, which can be parsed again.

| Path | Selects |
|---|---|
| `temperature`, `cloud.connected` | A field, a nested field. |
| `$.devices[0].name` | A field of the first array element. |
| `$.devices[-1:].deviceId` | The last element of an array. |
| `$[?(@.period == 1)].price` | Elements whose field matches a condition. |

**Example** — with `json` holding:

```json
{
  "firstName": "John",
  "lastName": "Doe",
  "age": 26,
  "address": {
    "streetAddress": "Naist street",
    "city": "Nara",
    "postalCode": "630-0192"
  }
}
```

```taphome
# field at the top level
PARSEJSON(json, "firstName");
# Result: "John"
# nested field
PARSEJSON(json, "address.city");
# Result: "Nara"
PARSEJSON(json, "age");
# Result: 26
# missing path returns Null, no error
PARSEJSON(json, "address.country", TRUE);
# Result: Null
```

`PARSEJSON(json, "address.country")` without the third argument stops the script with *PARSEJSON - Element not found: 'address.country'*.

**Example — loop over a JSON array**

With `TRUE`, `PARSEJSON` returns `Null` after the last element, which ends the loop:

```taphome
# loop counter and collected names
VAR i := 0;
VAR names := "";
# name of the first array element
VAR name := PARSEJSON(json, "$.devices[0].name", TRUE);
WHILE !ISNULL(name)
    names := names + name + "\n";
    i := i + 1;
    # name of the next element
    name := PARSEJSON(json, "$.devices[" + TOSTRING(i) + "].name", TRUE);
LOOP
# return the collected names
names;
```

**Errors** — *PARSEJSON - Element not found: 'path'*; *PARSEJSON - parse error: …* (invalid JSON); *PARSEJSON - argument 1 is null*.

## PARSEXML

`PARSEXML` reads a value from XML with an XPath expression and returns the value of the first matching node.

```text
PARSEXML(xml, xpath)
```

**Returns** — the value of the first node: a number when the text reads as a number, otherwise a string; `Null` when nothing matches. XPath functions return their own result, for example a number from `count()`.

**Remarks**

- Numbers in node text are read according to the language settings of the control unit. To read a number with a decimal point regardless of them, wrap the path in the XPath function `number()`.
- Namespaces declared in the document are registered automatically. A prefixed namespace (`xmlns:dc="…"`) is used with its prefix; a default namespace (`xmlns="…"`) gets the name of the element that declares it — for `<DIDL-Lite xmlns="…">` write `DIDL-Lite:container`.
- Documents smaller than 80 kB and compiled expressions are cached, so repeated calls on the same response are cheap.

**Example** — with the response holding:

```xml
<?xml version="1.0"?>
<catalog>
  <book id="bk101">
    <title>XML Developer's Guide</title>
    <price>44.95</price>
  </book>
  <book id="bk102">
    <title>Midnight Rain</title>
    <price>5.95</price>
  </book>
</catalog>
```

```taphome
# response body as XML text
VAR xml := response.Content;
# title of the second book
PARSEXML(xml, "//book[2]/title");
# Result: "Midnight Rain"
# attribute value
PARSEXML(xml, "//book[1]/@id");
# Result: "bk101"
# number() reads the price as a number with a decimal point
PARSEXML(xml, "number(//catalog/book[1]/price)");
# Result: 44.95
# count() returns the number of matching nodes
PARSEXML(xml, "count(//book)");
# Result: 2
# no match returns Null
PARSEXML(xml, "//catalog/magazine[1]/price");
# Result: Null
```

**Example — XML with namespaces**

```taphome
VAR xml := response.Content;
PARSEXML(xml, "//DIDL-Lite:container[dc:title='My Playlist']/DIDL-Lite:res");
```

**Errors** — *PARSEXML - parse error: …* (invalid XML or XPath).

**See also** — [SENDHTTPREQUEST](https://taphome.com/en/docs/script/packet-parser/#sendhttprequest), [DECODE](https://taphome.com/en/docs/script/data-type-conversions/#decode).
