# Parsing Logic That Extracts Job Requirements from CLI Detail Output

> Learn how parsing logic extracts job requirements from CLI detail output. Discover its dual-path strategy for HTML job posting analysis, prioritizing JSON-LD and then DOM parsing.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: how-to-guide
- Published: 2026-07-12

---

**The CLI `detail` command extracts job requirements by parsing HTML job postings using a dual-path strategy: first attempting JSON-LD schema extraction, then falling back to manual DOM parsing to populate the `description` field where requirements are stored.**

The parsing logic that extracts job requirements from CLI detail output operates within the `MadsLorentzen/ai-job-search` repository, specifically within the jobdanmark-search CLI tool. This command transforms raw HTML job postings into structured JSON objects, with the `description` field containing the full job text including requirements.

## Fetching and Parsing the HTML Source

The extraction begins with an HTTP request and DOM construction.

### Retrieving the Job Posting Page

In [`.agents/skills/jobdanmark-search/cli/src/commands/detail.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.agents/skills/jobdanmark-search/cli/src/commands/detail.ts) at lines 14-22, the command sends a `GET` request to `https://jobdanmark.dk/job/<slug>` to fetch the raw HTML content.

### Building the DOM Tree

The code uses `node-html-parser` to create a traversable DOM representation (`parse(html)`), referenced at line 90 in [`detail.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/detail.ts). This tree enables both structured data extraction and manual element querying.

## Dual-Path Extraction Strategy

The parsing logic implements a priority-based fallback system to maximize data accuracy.

### JSON-LD Schema Extraction (Primary Path)

**`findJobPostingJsonLd`** scans all `<script type="application/ld+json">` tags, parsing each block and returning the first object where `isJobPosting` validates the `@type` property as `JobPosting` (lines 85-87).

**`fromJsonLd`** then maps these structured fields directly onto the `DetailResult` type—including `title`, `datePosted`, `employmentType`, and `description`—as implemented at lines 89-99.

### Rendered HTML Extraction (Fallback Path)

When JSON-LD is absent, **`fromRenderedHtml`** manually extracts fields using CSS selectors:

- **Job Title**: Queries `.job-list-details .title`, falling back to `<h1>` or `<h3>` elements (lines 41-44)
- **Company Data**: Extracts organization name and logo from `companyLink` and `logoSrc` selectors (lines 50-55)
- **Overview Metadata**: **`overviewValue`** helper scans the job-overview list for labels like *Arbejdssted*, *Jobtype*, *Udgivet*, and *Ansøgningsfrist* (lines 22-32)
- **Description Construction**: Concatenates text from all `<p>` and `<li>` nodes within `.job-list-details` to build the complete job description containing requirements (lines 57-61)

## The Description Field: Where Requirements Reside

The **`description`** field of the resulting `DetailResult` object contains the full job posting text as plain text. Job requirements—such as required skills, experience levels, and qualifications—are embedded within this description.

At lines 91-92, **`parseJobPostingFromHtml`** returns the final object using either the JSON-LD or rendered-HTML path, ensuring the `description` is populated regardless of extraction method.

## URL Normalization and CLI Output

**`normalizeUrl`** (referenced at lines 58-63) converts relative application URLs (like `/apply`) into absolute URLs using `BASE_URL` defined in the helpers file.

The command supports two output formats:

- **JSON format** (`--format json`): Returns the complete `DetailResult` object
- **Plain text** (`--format plain`): Uses **`outputPlain`** (lines 56-70) to render human-readable output

## Code Examples

Fetch detailed job data including requirements:

```bash
bun run .agents/skills/jobdanmark-search/cli/src/cli.ts detail 12345 --format json

```

Sample output structure:

```json
{
  "slug": "12345",
  "url": "https://jobdanmark.dk/job/12345",
  "title": "Data Engineer",
  "datePosted": "2026-07-01",
  "validThrough": "2026-07-31",
  "employmentType": ["Fuldtid"],
  "hiringOrganization": { "name": "Acme Corp", "logo": "https://…" },
  "jobLocation": { "streetAddress": "Banegårdspladsen 1, 5000 Odense C" },
  "description": "We are looking for a data engineer ... **Requirements:**\n• Strong Python knowledge …\n• Experience with ETL pipelines …",
  "applyUrl": "https://acme.career.emply.com/apply/12345"
}

```

Extract requirements programmatically from the description:

```typescript
import { readFileSync } from "fs";

const result = JSON.parse(readFileSync("detail.json", "utf-8"));
const requirements = result.description.match(/Requirements:\s*([\s\S]*)/i)?.[1]?.trim();
console.log("Extracted requirements:\n", requirements);

```

## Summary

- The parsing logic extracts job requirements from the **`description`** field of the `DetailResult` object
- **JSON-LD extraction** via `findJobPostingJsonLd` and `fromJsonLd` provides structured data when available
- **Manual HTML parsing** via `fromRenderedHtml` serves as fallback, using `overviewValue` and DOM selectors
- Key files include [`.agents/skills/jobdanmark-search/cli/src/commands/detail.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.agents/skills/jobdanmark-search/cli/src/commands/detail.ts) and [`.agents/skills/jobdanmark-search/cli/src/helpers.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.agents/skills/jobdanmark-search/cli/src/helpers.ts)
- The `node-html-parser` library creates the DOM tree used for element extraction
- Requirements remain embedded in plain text within the `description` field, extractable via regex or string parsing

## Frequently Asked Questions

### How does the detail command handle job postings without JSON-LD metadata?

When JSON-LD is absent, the code automatically falls back to `fromRenderedHtml`, which manually scrapes the DOM using CSS selectors like `.job-list-details .title` and extracts the description by concatenating `<p>` and `<li>` elements.

### Where exactly are the job requirements stored in the output?

Job requirements reside within the **`description`** field of the returned `DetailResult` object. This field contains the complete job posting text as plain text, including sections labeled "Requirements," qualifications, and desired skills.

### Can I extract structured requirement fields separately from the description?

The current implementation does not parse individual requirements into separate fields; they remain part of the unified `description` string. You must post-process the description using pattern matching or natural language processing to isolate specific requirements.

### What dependencies does the parsing logic require?

The extraction logic relies on `node-html-parser` for DOM manipulation and standard Node.js HTTP clients for fetching. Helper utilities for URL normalization and text cleaning are imported from [`.agents/skills/jobdanmark-search/cli/src/helpers.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.agents/skills/jobdanmark-search/cli/src/helpers.ts).