Johnny John Boy
Johnny John Boy

Reputation: 3283

How to render a Jinja2 template field with correct capitalisation depending on field location?

I am trying to render an HTML field with the same string, in this example it's "pots and pans". I need to ensure that if the {{ example_field }} is at the beginning of sentence it is capitalised and if not it's lowercase.

I've tried numerous iterations on the following and this is where I got to which does not work.

from jinja2 import Environment, PackageLoader, select_autoescape

environment = Environment()

EXAMPLE_BODY_1 = """
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Example</title>
  </head>
  <body>
    <div><h2>Example Contract Term</h2></div>
    <div>
      <p>
        Sometimes the example_field is in the middle so needs to be lowercase,
        {{ example_field }} is a good example.
      </p>
      <ul>
        <i>All terms in this example are binding.</i>
        <i>The terms are made up as this is an example.</i>
        <i>Terms can always change.</i>
      </ul>
    </div>

    <div><h2>Example Contract Other Term</h2></div>
    <div>
      <p>
        {{ example_field }} can also be at the start of a sentence to therefore
        needs to be capitalised.
      </p>
      <ul>
        <i>Sometimes it's like the first example.</i>
        <i>The terms are made up as this is an example.</i>
        <i>Terms can always change.</i>
      </ul>
    </div>
  </body>
</html>
"""

def capitalize_if_start_of_html_sentence(value, html_content):
    # Normalize whitespace and remove HTML tags
    content = ' '.join(html_content.split())
    
    # Split the content into sentences using common sentence-ending punctuation
    sentences = content.split('. ')
    
    for sentence in sentences:
        # Further split by other sentence-ending punctuation
        sub_sentences = sentence.split('? ')
        for sub_sentence in sub_sentences:
            sub_sub_sentences = sub_sentence.split('! ')
            for sub_sub_sentence in sub_sub_sentences:
                # Check if the sub-sentence starts with the example_field placeholder
                if sub_sub_sentence.startswith('{{ example_field }}'):
                    return value.capitalize()
    return value.lower()

# Add the custom filter to the environment
environment.filters['capitalize_if_start_of_html_sentence'] = lambda value: capitalize_if_start_of_html_sentence(value, EXAMPLE_BODY_1)

# Create a template from string
template = environment.from_string(EXAMPLE_BODY_1)

example_merge_field = "pots and pans"

# Render the template with the custom filter applied
print(template.render(example_field=example_merge_field))

# Apply the filter manually to the example_field
capitalized_example_field = capitalize_if_start_of_html_sentence(example_merge_field, EXAMPLE_BODY_1)

# Render the template with the manually capitalized field
print(template.render(example_field=capitalized_example_field))

I also tried using HTMLParser as the data contents do have the correct {{ example_field }} then the text extracted which I could do starts with but I can't work it out.

from html.parser import HTMLParser

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Encountered a start tag:", tag)

    def handle_data(self, data):
        print("Data     :", data)

This is what I am trying to achieve:

# Expected output
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Example</title>
  </head>
  <body>
    <div><h2>Example Contract Term</h2></div>
    <div>
      <p>
        Sometimes the example_field is in the middle so needs to be lowercase,
        pots and pans is a good example.
      </p>
      <ul>
        <i>All terms in this example are binding.</i>
        <i>The terms are made up as this is an example.</i>
        <i>Terms can always change.</i>
      </ul>
    </div>

    <div><h2>Example Contract Other Term</h2></div>
    <div>
      <p>Pots and pans can also be at the start of a sentence to therefore
        needs to be capitalised.
      </p>
      <ul>
        <i>Sometimes it's like the first example.</i>
        <i>The terms are made up as this is an example.</i>
        <i>Terms can always change.</i>
      </ul>
    </div>
  </body>
</html>

Upvotes: 0

Views: 31

Answers (1)

Sean Vieira
Sean Vieira

Reputation: 160043

Presuming that the template is allowed to know where the variable interpolation is in the sentence you should be able to get away with simply inserting a call to the capitalize filter:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Example</title>
  </head>
  <body>
    <div><h2>Example Contract Term</h2></div>
    <div>
      <p>
        Sometimes the example_field is in the middle so needs to be lowercase,
        {{ example_field }} is a good example.
      </p>
      <ul>
        <i>All terms in this example are binding.</i>
        <i>The terms are made up as this is an example.</i>
        <i>Terms can always change.</i>
      </ul>
    </div>

    <div><h2>Example Contract Other Term</h2></div>
    <div>
      <p>
        {{ example_field | capitalize }} can also be at the start of a sentence to therefore
        needs to be capitalised.
      </p>
      <ul>
        <i>Sometimes it's like the first example.</i>
        <i>The terms are made up as this is an example.</i>
        <i>Terms can always change.</i>
      </ul>
    </div>
  </body>
</html>

Upvotes: -1

Related Questions