瀏覽代碼

move xslt/xml into templates

Daniel Sheffield 1 年之前
父節點
當前提交
c00c43e1de
共有 5 個文件被更改,包括 184 次插入99 次删除
  1. 0 0
      requirements.txt
  2. 2 2
      rest/Dockerfile
  3. 34 97
      rest/pyapi.py
  4. 141 0
      rest/query-to-xml-xslt.tpl
  5. 7 0
      rest/query-to-xml.tpl

+ 0 - 0
rest/requirements.txt → requirements.txt


+ 2 - 2
rest/Dockerfile

@@ -2,5 +2,5 @@ FROM python:3-slim
 WORKDIR /usr/src/app
 COPY  requirements.txt ./
 RUN pip install --no-cache-dir -r requirements.txt
-COPY pyapi.py .
-CMD [ "python", "./pyapi.py" ]
+COPY rest rest
+CMD [ "python", "rest/pyapi.py" ]

+ 34 - 97
rest/pyapi.py

@@ -1,8 +1,9 @@
-# Copyright (c) Daniel Sheffield 2022
+# Copyright (c) Daniel Sheffield 2022 - 2023
 # All rights reserved.
 from bottle import route, request, run, template, response, abort
 import psycopg
-from psycopg import Cursor, sql
+from psycopg import Cursor
+from psycopg.sql import SQL, Literal
 import os
 host = f"host={os.getenv('HOST')}"
 db = f"dbname={os.getenv('DB', 'pgdb')}"
@@ -11,104 +12,30 @@ password = f"password={os.getenv('PASSWORD','')}"
 if not password.split('=',1)[1]:
     password = ''
 conn: Cursor = psycopg.connect(f"{host} {db} {user} {password}")
-random_statement = """SELECT
-  query_to_xml('SELECT category, translation, reference, txt
-    FROM pg_random_view_default_if_null
-    JOIN pg_categories ON category = name
-    ORDER BY tableid ASC',
-  false, false, ''::text);"""
-specified_statement = sql.SQL("""SELECT query_to_xml($$SELECT category, translation, reference, txt
-  FROM getprayer(
-    {categories}::text[],
-    {translations}::text[],
-    {references}::text[]
-  ) ORDER BY ordinal ASC$$, false, false, ''::text);""")
-heading = """<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="https://shandan.one/xml/pg_view_style.xsl"?>
-"""
-random_schema = """
-<xsd:schema
-    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
-
-<xsd:simpleType name="UDT.pgdb.pg_catalog.text">
-  <xsd:restriction base="xsd:string">
-  </xsd:restriction>
-</xsd:simpleType>
-
-<xsd:simpleType name="VARCHAR">
-  <xsd:restriction base="xsd:string">
-  </xsd:restriction>
-</xsd:simpleType>
-
-<xsd:complexType name="RowType.pgdb.public.pg_random_view_default_if_null">
-  <xsd:sequence>
-    <xsd:element name="category" type="UDT.pgdb.pg_catalog.text" minOccurs="0"></xsd:element>
-    <xsd:element name="translation" type="VARCHAR" minOccurs="0"></xsd:element>
-    <xsd:element name="reference" type="UDT.pgdb.pg_catalog.text" minOccurs="0"></xsd:element>
-    <xsd:element name="txt" type="VARCHAR" minOccurs="0"></xsd:element>
-  </xsd:sequence>
-</xsd:complexType>
-
-<xsd:complexType name="TableType.pgdb.public.pg_random_view_default_if_null">
-  <xsd:sequence>
-    <xsd:element name="row" type="RowType.pgdb.public.pg_random_view_default_if_null" minOccurs="0" maxOccurs="unbounded"/>
-  </xsd:sequence>
-</xsd:complexType>
-
-<xsd:element name="table" type="TableType.pgdb.public.pg_random_view_default_if_null"/>
-
-</xsd:schema>
-"""
-specified_heading = heading + """
-<xsd:element name="table" type="TableType.pgdb.public.pg_view"/>
-
-</xsd:schema>
-"""
-specified_schema = """
-<xsd:schema
-    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
-
-<xsd:simpleType name="UDT.pgdb.pg_catalog.text">
-  <xsd:restriction base="xsd:string">
-  </xsd:restriction>
-</xsd:simpleType>
-
-<xsd:simpleType name="VARCHAR">
-  <xsd:restriction base="xsd:string">
-  </xsd:restriction>
-</xsd:simpleType>
-
-<xsd:complexType name="RowType.pgdb.public.pg_view">
-  <xsd:sequence>
-    <xsd:element name="category" type="UDT.pgdb.pg_catalog.text" minOccurs="0"></xsd:element>
-    <xsd:element name="translation" type="VARCHAR" minOccurs="0"></xsd:element>
-    <xsd:element name="reference" type="UDT.pgdb.pg_catalog.text" minOccurs="0"></xsd:element>
-    <xsd:element name="txt" type="VARCHAR" minOccurs="0"></xsd:element>
-  </xsd:sequence>
-</xsd:complexType>
-
-<xsd:complexType name="TableType.pgdb.public.pg_view">
-  <xsd:sequence>
-    <xsd:element name="row" type="RowType.pgdb.public.pg_view" minOccurs="0" maxOccurs="unbounded"/>
-  </xsd:sequence>
-</xsd:complexType>
-
-<xsd:element name="table" type="TableType.pgdb.public.pg_view"/>
-
-</xsd:schema>
-"""
-
 
 @route('/pyapi/random')
 def random():
     try:
         with conn.cursor() as cur:
-            xml = cur.execute(random_statement).fetchone()[0].splitlines()
+            inner = SQL("""
+SELECT category, translation, reference, txt
+FROM pg_random_view_default_if_null
+JOIN pg_categories ON category = name
+ORDER BY tableid ASC
+""")
+            xml = cur.execute(SQL("""
+SELECT query_to_xml_and_xmlschema({q}, false, false, ''::text);
+""").format(q=inner.as_string(cur))).fetchone()[0]
     finally:
         conn.commit()
     response.content_type = 'application/xhtml+xml; charset=utf-8'
-    return f"{heading}{xml[0]}{random_schema}" + '\n'.join(xml[1:])
+    return template("rest/query-to-xml", title="Random Prayer Generator", xml=xml)
 
+@route('/pyapi/xslt')
+def table():
+    title = request.query['title'] if 'title' in request.query.keys() else None
+    response.content_type = 'application/xhtml+xml; charset=utf-8'
+    return template("rest/query-to-xml-xslt", title=title)
 
 @route('/pyapi/pg')
 def specified():
@@ -144,14 +71,24 @@ def specified():
 
     try:
         with conn.cursor() as cur:
-            xml = cur.execute(specified_statement.format(
-                categories=sql.Literal(categories),
-                translations=sql.Literal(translations),
-                references=sql.Literal(references)
-            )).fetchone()[0].splitlines()
+            inner = SQL("""
+SELECT category, translation, reference, txt
+    FROM getprayer(
+        {categories}::text[],
+        {translations}::text[],
+        {references}::text[]
+    ) ORDER BY ordinal ASC
+""").format(
+    categories=Literal(categories),
+    translations=Literal(translations),
+    references=Literal(references)
+)
+            xml = cur.execute(SQL("""
+SELECT query_to_xml_and_xmlschema({q}, false, false, ''::text);
+""").format(q=Literal(inner.as_string(cur)))).fetchone()[0]
     finally:
         conn.commit()
     response.content_type = 'application/xhtml+xml; charset=utf-8'
-    return f"{heading}{xml[0]}{specified_schema}" + '\n'.join(xml[1:])
+    return template("rest/query-to-xml", title="Prayer Generator", xml=xml)
 
 run(host='0.0.0.0', port=11888)

+ 141 - 0
rest/query-to-xml-xslt.tpl

@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) Daniel Sheffield 2022
+All rights reserved.
+-->
+<xsl:stylesheet version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns="http://www.w3.org/1999/xhtml"
+>
+
+  <xsl:output method="xml"
+      doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
+      doctype-public="-//W3C/DTD XHTML 1.0 Strict//EN"
+      indent="yes"/>
+
+  <xsl:template match="/*">
+    <xsl:variable name="schema" select="//xsd:schema"/>
+    <xsl:variable name="tabletypename"
+                  select="$schema/xsd:element[@name=name(current())]/@type"/>
+    <xsl:variable name="rowtypename"
+                  select="$schema/xsd:complexType[@name=$tabletypename]/xsd:sequence/xsd:element[@name='row']/@type"/>
+
+    <html>
+      <head>
+        <title>{{title}}</title>
+	<meta name="description" content="Generate a template prayer following the form of the model prayer outlined in Matthew 6:9‑13 and Luke 11:2‑4"/>
+	<meta name="keywords" content="Bible, Prayer, Generator, SWORD"/>
+	<meta name="author" content="Daniel Sheffield"/>
+	<meta name="viewport" content="width=device-width, initial-scale=1"/>
+	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/purecss@2.1.0/build/pure-min.css" integrity="sha384-yHIFVG6ClnONEA5yB5DJXfW2/KC173DIQrYoZMEtBvGzmf0PKiGyNEqe9N6BNDBH" crossorigin="anonymous"/>
+	<link rel="stylesheet" href="https://shandan.one/css/grids-responsive-min.css"/>
+	<link rel="stylesheet" href="https://shandan.one/css/responsive-visibility-collapse.css"/>
+        <style>
+span.engraved {
+    color: #A8A8A8;
+    font-size: 0.8em;
+    text-shadow: 0px 0.1em 0px rgba(168,168,168,.1), 0px -0.1em 0px rgba(0,0,0,.7);
+    float: right;
+}
+	</style>
+      </head>
+      <body>
+        <div style="background: darkgray; position: sticky; top: 0; margin: 0; padding: 0; width: 100%; z-index: 1; text-align: center;">
+        <form action="random">
+          <button type="submit" style="margin: 0.2em">Generate</button>
+          <span style="position: absolute; right: 0; padding: 0.4em">
+          <a>
+          <xsl:attribute name="href">./pg?<xsl:for-each select="//row"><xsl:value-of select="category"/>=<xsl:value-of select="translate(reference,' ','')"/>+<xsl:value-of select="translation"/><xsl:if test="position() != last()">&#038;</xsl:if></xsl:for-each></xsl:attribute>
+          Permalink
+          </a>
+          </span>
+	</form>
+        </div>
+        <div style="position: relative; max-width: 68em; min-width: min(100%, 68em); left: 50%; transform: translate(max(-50%, -34em),0)">
+        <table class="pure-table pure-table-bordered pure-table-striped">
+          <tr style="text-transform: capitalize">
+            <xsl:for-each select="$schema/xsd:complexType[@name=$rowtypename]/xsd:sequence/xsd:element/@name">
+                <xsl:variable name="elementtype"
+                              select="."/>
+                <xsl:choose>
+                <xsl:when test="$elementtype = 'txt'">
+              <th class="opt-all">Text</th>
+                </xsl:when>
+                <xsl:when test="$elementtype = 'category'">
+              <th class="opt-all">Section</th>
+                </xsl:when>
+                <xsl:when test="$elementtype = 'translation'">
+              <th class="opt-md opt-lg opt-xl opt-xxl">Reference</th>
+                </xsl:when>
+                <xsl:otherwise>
+                </xsl:otherwise>
+                </xsl:choose>
+            </xsl:for-each>
+          </tr>
+
+          <xsl:for-each select="row">
+            <tr>
+              <xsl:for-each select="*">
+                <xsl:variable name="elementtype"
+                              select="name(current())"/>
+                <xsl:choose>
+                <xsl:when test="$elementtype = 'txt'">
+                <td class="opt-all" style="text-align: justify"><xsl:value-of select="."/>&#160;<span class="engraved">
+                <xsl:value-of select="../translation"/>
+                </span>
+                </td>
+                </xsl:when>
+                <xsl:when test="$elementtype = 'category'">
+                  <xsl:choose>
+                  <xsl:when test="contains(.,'z_')">
+                  <td class="opt-all" rowspan="2" style="text-transform: capitalize;">Kingdom</td>
+                  </xsl:when>
+                  <xsl:when test="contains(.,'a_')">
+                  </xsl:when>
+		  <xsl:otherwise>
+                  <td class="opt-all" style="text-transform: capitalize;"><xsl:value-of select="."/></td>
+                  </xsl:otherwise>
+                  </xsl:choose>
+                </xsl:when>
+                <xsl:when test="$elementtype = 'translation'">
+                </xsl:when>
+                <xsl:otherwise>
+                  <td class="opt-md opt-lg opt-xl opt-xxl">
+                  <xsl:value-of select="translate(translate(.,' ','&#160;'),'-','&#8209;')"/>
+                  <br/>
+                  <a>
+                  <xsl:attribute name="href">/license/<xsl:value-of select="preceding-sibling::translation"/>.txt</xsl:attribute>
+                  <xsl:value-of select="preceding-sibling::translation"/>
+                  </a>
+                  </td>
+                </xsl:otherwise>
+                </xsl:choose>
+              </xsl:for-each>
+            </tr>
+          </xsl:for-each>
+        <tfoot style="line-height: 1.4">
+        <tr>
+          <td colspan="3">
+          Copyright (c) Daniel Sheffield 2022. All right reserved.
+          <br/>
+          Powered <a href="https://www.crosswire.org/jsword/">JSword</a> an implementation of <a href="https://www.crosswire.org/sword/index.jsp">The SWORD Project</a>'s SWORD API brought to you by the <a href="https://crosswire.org">The CrossWire Bible Society</a>.
+          <br/>
+          Quotes are taken from various translations as indicated. See
+          <xsl:for-each select="//row/translation[not(.=preceding::*)]">
+          <a>
+          <xsl:attribute name="href">/license/<xsl:value-of select="."/>.txt</xsl:attribute>
+          <xsl:value-of select="."/>
+          </a>,
+          </xsl:for-each>
+          for the license and copyright information of each respective work.
+          </td>
+        </tr>
+        </tfoot>
+        </table>
+        </div>
+      </body>
+    </html>
+  </xsl:template>
+
+</xsl:stylesheet>

+ 7 - 0
rest/query-to-xml.tpl

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) Daniel Sheffield 2022
+All rights reserved.
+-->
+<?xml-stylesheet type="text/xsl" href="/pyapi/xslt?title={{title}}"?>
+{{!xml}}