t4g 0.0.1.dev3
Tag Generator
License: MIT License
Requires Python: >=3.6

# Tag Generator

This is a tag generator for Python3.

You can use this to generate XML and HTML.

The aim of this library is to make the generation of XML and HTML
from python easier and more readable.

<p align="center">
<a href="https://github.com/n1y7n/t4g/actions?query=workflow%3ATest" target="_blank">
    <img src="https://github.com/n1y7n/t4g/workflows/Test/badge.svg" alt="Test">
</a>
<a href="https://codecov.io/gh/n1y7n/t4g" target="_blank">
    <img src="https://img.shields.io/codecov/c/github/n1y7n/t4g?color=%2334D058" alt="Coverage">
</a>
<a href="https://pypi.org/project/t4g" target="_blank">
    <img src="https://img.shields.io/pypi/v/t4g?color=%2334D058&label=pypi%20package" alt="Package version">
</a>
</p>


## Examples

    with Page() as page:
        page.title = 'The Title'
        with page.head as head:
            head + Tag('script') + 'This is some script'
        with page.body as body:
            body + 'This is some body text'

The previous script produces the following HTML document.

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <title>The Title</title>
    <script>This is some script</script>
    </head>
    <body>
    This is some body text
    </body>
    </html>

This library has base structures to allow the construction of arbitrary HTML.
It also has enhanced tag definitions to make defining the structure
of the document more readable within Python.

## Base structures

| Element   | Purpose |
| --------- | ------- |
| Tag       | Define any HTML or XML tag |
| Attribute | A container for the text of an attribute key or value |
| Text      | A container for HTML formatted text |

Any Tag that has no content is automatically converted into a closed tag.

The string representation of any Tag is the rendered value of the tag and all children.
It is not rendered with new line characters after tags in order to save space in the output.
Text that contains new line characters is retained in the output.

## HTML structures

| Element   | Purpose |
| --------- | ------- |
| Body      | body tag |
| Div       | div tag |
| DocType   | doctype tag |
| H         | heading tags |
| H1        | h1 tag |
| H2        | h2 tag |
| H3        | h3 tag |
| H4        | h4 tag |
| H5        | h5 tag |
| Head      | head tag |
| Html      | html tag |
| Input     | input tag |
| Meta      | meta tag |
| P         | paragraph tag |
| Title     | title tag |

Other tags will be defined in time.
However the base Tag() element can be used
to construct any needed tag.

## Combining Tags

The library does not restrict which tags can be composed within which other tags.
This is to maintain maximum flexibility and allow generation of both XML and HTML. 
To aid with correct HTML some helper properties are provided.

### Adding content to Tags

Content can be added to another tag in several different ways.

To append to the end of the existing tag content you can use the *append()* method on the tag.

    tag = Tag('h1')
    tag.append('This is a heading')
    assert str(tag) == '<h1>This is a heading</h1>'

It is also possible to use the add operator to append to the end of the existing tag content.

    tag = Tag('h1')
    tag + 'This is a heading'
    assert str(tag) == '<h1>This is a heading</h1>'

It is possible to chain additions if it makes sense.

    page = Tag()
    page + Tag('html') + Tag('head') + Tag('title') + 'This is a title'
    assert str(page) == '<html><head><title>This is a title</title></head></html>'

To create an instruction tag, which cannot take content, use the instruction attribute flag.

    doctype = Tag('!DOCTYPE', is_instruction=True, instruction_text='html')
    assert str(doctype) == '<!DOCTYPE html>'

To create an enforced, which cannot take content, tag use the closed attribute flag.

    br = Tag('br', is_closed=True)
    assert str(br) == '<br />'

Other HTML tags such as input, which cannot take content, can also be constructed.

    input = Tag('input', is_instruction=True)
    input['type'] = 'text'
    input['name'] = 'username'
    assert str(input) == '<input type="text" name="username">'

However it is often more readable to use the inbuilt custom tags for things like this.

    input = Input(type='text', name='username')
    assert str(input) == '<input type="text" name="username">'


### Inserting content into Tags

Content can be inserted into another tag in several different ways.

To insert you can use the *insert()* method on the tag.

    tag = Tag('h1')
    tag + 'This'
    tag + 'Heading'
    tag.insert(1, ' is a ')
    assert str(tag) == '<h1>This is a Heading</h1>'

It is also possible to use the add operator to insert into the tag content.

    tag = Tag('h1')
    tag + 'This'
    tag + 'Heading'
    tag + (1, ' is a ')
    assert str(tag) == '<h1>This is a Heading</h1>'

### Setting attribute values on Tags

It is possible to set an attribute on a tag using the index operator.

    tag = Tag('h1')
    tag['class'] = 'red'
    tag + 'This is a heading'
    assert str(tag) == '<h1 class="red">This is a heading</h1>'

It is important to remember that the attribute name must be a string.

### Accessing the elements of the Tag's content

It is possible to access the elements of the tag's content using the index operator.

    tag = Tag('h1')
    tag + 'This'
    tag + ' is a '
    tag + 'Heading'
    assert tag[1] == ' is a ' 

It is also possible to get the number of content elements using the len operator.

    tag = Tag('h1')
    tag + 'This'
    tag + ' is a '
    tag + 'Heading'
    assert len(tag) == 3

The index of a particular element in the content of a tag can also be found using the *index()* method.

    tag = Tag('h1')
    tag + 'This'
    tag + ' is a '
    tag + 'Heading'
    assert tag.index(' is a ') == 1

The slice operator can be used to slice the content of the tag.

    tag = Tag('h1')
    tag + 'This'
    tag + ' is a '
    tag + 'Heading'
    tag[1:2] = [' is also', ' a ']
    assert str(tag) == '<h1>This is also a Heading</h1>'

An attribute value can be accessed with the item operator.

    tag = Tag('h1')
    tag['class'] = 'red'
    assert tag['class'] == 'red'

### Removing content from a tag

The entire content of a tag can be cleared with the *clear()* method.
This will clear not only the content but also the attributes of the tag.

    tag = Tag('h1')
    tag['class'] = 'red'
    tag + 'This'
    tag + ' is a '
    tag + 'Heading'
    tag.clear()
    assert str(tag) == '<h1 />'

An element can be removed from the tag content using the *sub* operator.

    tag = Tag('h1')
    tag['class'] = 'red'
    tag + 'This'
    tag + ' is a '
    tag + 'Heading'
    tag - ' is a '
    assert str(tag) == '<h1 class="red">ThisHeading</h1>'
    
An element can also be removed from the tag content using the *remove()* method.

    tag = Tag('h1')
    tag['class'] = 'red'
    tag + 'This'
    tag + ' is a '
    tag + 'Heading'
    tag.remove(' is a ')
    assert str(tag) == '<h1 class="red">ThisHeading</h1>'

An element can be deleted from the content by position using the delete operator.

    tag = Tag('h1')
    tag['class'] = 'red'
    tag + 'This'
    tag + ' is a '
    tag + 'Heading'
    del tag[1]
    assert str(tag) == '<h1 class="red">ThisHeading</h1>'

An attribute can also be removed from the tag using the delete operator.

    tag = Tag('h1')
    tag['class'] = 'red'
    tag + 'This'
    tag + ' is a '
    tag + 'Heading'
    del tag['class']
    assert str(tag) == '<h1>This is a Heading</h1>'