QwQ Tag
A lightweight Python library for parsing XML/HTML content into structured, type-safe objects using Pydantic models. qwq-tag provides a simple and intuitive way to work with XML/HTML data while maintaining strong type safety and validation.
Features
- 🚀 Simple API: Parse XML/HTML strings with a single method call
- 🔒 Type Safety: Built on Pydantic for robust data validation and type hints
- 🌐 Flexible Parsing: Handles malformed XML/HTML with recovery parsing
- 📦 Lightweight: Minimal dependencies (only
lxmlandpydantic) - 🎯 Mixed Content Support: Properly handles text and nested elements
- 🔄 Multiple Root Elements: Can parse fragments with multiple top-level elements
- 🧹 Clean Output: Automatically handles whitespace normalization
Installation
Using pip
pip install qwq-tag
Using PDM
pdm add qwq-tag
Requirements
- Python 3.10+
- lxml >= 6.0.0
- pydantic >= 2.11.7
Quick Start
from qwq_tag import QwqTag
# Parse simple XML
html = '<div class="container">Hello World</div>'
tags = QwqTag.from_str(html)
# Access the parsed content
tag = tags[0]
print(tag.name) # "div"
print(tag.content) # ["Hello World"]
print(tag.attr) # {"class": "container"}
print(tag.content_text) # "Hello World"
Usage Examples
Basic XML Parsing
from qwq_tag import QwqTag
# Simple element with attributes
xml = '<p class="text" id="intro">Hello World</p>'
result = QwqTag.from_str(xml)
tag = result[0]
print(f"Tag: {tag.name}") # Tag: p
print(f"Content: {tag.content}") # Content: ['Hello World']
print(f"Class: {tag.attr['class']}") # Class: text
print(f"ID: {tag.attr['id']}") # ID: intro
Nested Elements
# Nested structure
xml = """
<div class="container">
<h1>Title</h1>
<p>Paragraph content</p>
</div>
"""
result = QwqTag.from_str(xml)
div_tag = result[0]
print(f"Container has {len(div_tag.content)} children")
for child in div_tag.content:
if isinstance(child, QwqTag):
print(f"- {child.name}: {child.content_text}")
Mixed Content (Text + Elements)
# Mixed content with text and nested elements
xml = '<p>Before <strong>bold text</strong> and <em>italic</em> after</p>'
result = QwqTag.from_str(xml)
p_tag = result[0]
print("Content breakdown:")
for item in p_tag.content:
if isinstance(item, str):
print(f" Text: '{item}'")
else:
print(f" Element: <{item.name}>{item.content_text}</{item.name}>")
# Output:
# Text: 'Before'
# Element: <strong>bold text</strong>
# Text: 'and'
# Element: <em>italic</em>
# Text: 'after'
Multiple Root Elements
# Fragment with multiple root elements
xml = '<h1>Title</h1><p>First paragraph</p><p>Second paragraph</p>'
result = QwqTag.from_str(xml)
print(f"Found {len(result)} root elements:")
for tag in result:
print(f"- {tag.name}: {tag.content_text}")
# Output:
# Found 3 root elements:
# - h1: Title
# - p: First paragraph
# - p: Second paragraph
Error Recovery
# Malformed XML/HTML
malformed = '<div><p>Unclosed paragraph<span>Text</div>'
try:
result = QwqTag.from_str(malformed)
print("Successfully parsed malformed XML!")
print(str(result[0]))
except Exception as e:
print(f"Parsing failed: {e}")
Converting Back to String
# Create a tag programmatically
tag = QwqTag(
name="article",
content=["Article content"],
attr={"class": "post", "id": "123"}
)
print(str(tag))
# Output: <article class="post" id="123">Article content</article>
Development
Setup Development Environment
# Clone the repository
git clone https://github.com/yanli/qwq-tag.git
cd qwq-tag
# Install PDM if you haven't already
pip install pdm
# Install dependencies
pdm install
# Install development dependencies
pdm install -G dev
Running Tests
# Run all tests
pdm run test
# Run with coverage
pdm run pytest --cov=qwq_tag tests/
# Run specific test file
pdm run pytest tests/test_qwq_tag.py
Code Quality
# Format code
pdm run fix
# Check code quality
pdm run check
Available Scripts
pdm run test- Run the test suitepdm run fix- Auto-fix code formatting and linting issuespdm run check- Check code formatting and linting without making changes
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Development Workflow
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for your changes
- Run the test suite (
pdm run test) - Check code quality (
pdm run check) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Release files for qwq-tag 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| qwq_tag-0.1.2.tar.gz | 10.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qwq_tag-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 15.3 kB
Release files / qwq_tag-0.1.2.tar.gz
| Download URL | qwq_tag-0.1.2.tar.gz |
|---|---|
| Size | 10.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e5c0d89de168a5b0057c25dd9a6ad00ae6bfc7ea488baa2ecb217cd0e97be84d
|
|
BLAKE2b-256 checksum How to use checksums |
1b2c81fc7afeb777a017dae72ae536005645b630c5249e9a31e9f50ede274990
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
pdm/2.25.6 CPython/3.13.5 Linux/6.11.0-1018-azure
|
Release files / qwq_tag-0.1.2-py3-none-any.whl
| Download URL | qwq_tag-0.1.2-py3-none-any.whl |
|---|---|
| Size | 4.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c8dada889c92101ad14dbdae366d9bb31fb080f9f38d9daeaa66b1b4b9e2a79d
|
|
BLAKE2b-256 checksum How to use checksums |
d154e3d4e4e5898e6a976236ad8ec6e963664aec52f4ffe41b2fbafcbb32d725
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
pdm/2.25.6 CPython/3.13.5 Linux/6.11.0-1018-azure
|