Custom widgets: The equivalent of Mako's <%def> in Jinja2 or Django templates - django-templates

I am quite proficient with Mako, but never actually used Jinja or Django templates.
What is Jinja/Django equivalent of Mako <%def name="..."> definition?
Following is a simplified example of my actual use case. I need to define a simple table and use it repeatedly on the page:
<%def name="temperature_table(north, east, south, west)">
<table>
<tr>
<td>North:</td>
<td>${north}</td>
</tr>
<tr>
<td>East:</td>
<td>${east}</td>
</tr>
<tr>
<td>South:</td>
<td>${south}</td>
</tr>
<tr>
<td>West:</td>
<td>${west}</td>
</tr>
</table>
</%def>
<h2>Morning</h2>
${weather_table(20, 21, 22, 23)}
<h2>Afternoon</h2>
${weather_table(22, 22, 25, 24)}
<h2>Night</h2>
${weather_table(17, 16, 17, 18)}
From what I gleaned from various articles, it could seem that blocks are used for this purpose in Jinja/Django. But blocks would introduce inheritance even to simple templates where a custom widget would be sufficient. Other authors suggest creating a custom tag, but, in my opinion, this would require to write custom parsing, rendering, and probably even custom cache managing functions. Am I missing something?

You can use a macro for that.
As described in the manual:
Macros are comparable with functions in regular programming languages. They are useful to put often used idioms into reusable functions to not repeat yourself (“DRY”).
Source: https://jinja.palletsprojects.com/en/3.0.x/templates/#macros
So, given:
{% macro weather_table(north, east, south, west) -%}
<table>
<tr>
<td>North:</td>
<td>{{ north }}</td>
</tr>
<tr>
<td>East:</td>
<td>{{ east }}</td>
</tr>
<tr>
<td>South:</td>
<td>{{ south }}</td>
</tr>
<tr>
<td>West:</td>
<td>{{ west }}</td>
</tr>
</table>
{%- endmacro %}
<h2>Morning</h2>
{{ weather_table(20, 21, 22, 23) }}
<h2>Afternoon</h2>
{{ weather_table(22, 22, 25, 24) }}
<h2>Night</h2>
{{ weather_table(17, 16, 17, 18) }}
It renders your expected tables.
<h2>Morning</h2>
<table>
<tr>
<td>North:</td>
<td>20</td>
</tr>
<tr>
<td>East:</td>
<td>21</td>
</tr>
<tr>
<td>South:</td>
<td>22</td>
</tr>
<tr>
<td>West:</td>
<td>23</td>
</tr>
</table>
<h2>Afternoon</h2>
<table>
<tr>
<td>North:</td>
<td>22</td>
</tr>
<tr>
<td>East:</td>
<td>22</td>
</tr>
<tr>
<td>South:</td>
<td>25</td>
</tr>
<tr>
<td>West:</td>
<td>24</td>
</tr>
</table>
<h2>Night</h2>
<table>
<tr>
<td>North:</td>
<td>17</td>
</tr>
<tr>
<td>East:</td>
<td>16</td>
</tr>
<tr>
<td>South:</td>
<td>17</td>
</tr>
<tr>
<td>West:</td>
<td>18</td>
</tr>
</table>

Related

Laravel 9 Calculate minute difference same_id all the data in the table individually

I had already opened a discussion about this and I was given a solution only that the solution calculates everything continuous without interrupting every different same_id, I should finish counting when same_id changes and start counting again, does anyone have ideas to help me solve this problem?
<table>
<thead>
<tr>
<th>id</th>
<th>timestamp</th>
<th>states</th>
<th>same_id</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2023-01-11 15:26:23</td>
<td>NotAvailable</td>
<td>80</td>
<td>2</td>
<td>2023-01-11 15:26:55</td>
<td>ToBeAssigned</td>
<td>80</td>
<td>3</td>
<td>2023-01-11 15:27:06</td>
<td>Assigned</td>
<td>80</td>
<td>3</td>
<td>2023-01-11 15:27:19</td>
<td>TakingCharge</td>
<td>80</td>
<td>4</td>
<td>2023-01-11 15:29:05</td>
<td>Closed</td>
<td>80</td>
</tr>
</tbody>
</table>
the solution that was proposed to me and it works is this but it doesn't stop counting when the same_id changes and I should do this
<table>
<thead>
<tr>
<th>id</th>
<th>timestamp</th>
<th>states</th>
<th>delay</th>
</tr>
</thead>
<tbody>
#foreach((array)$tickets_logs as $i => $ticket_log)
<tr>
<td>{{ $ticket_log['id'] }}</td>
<td>{{ __($ticket_log['states']) }}</td>
<td>{{ $ticket_log['time_stamp'] }}</td>
<td>
#if(!$loop->first)
{{ (new Carbon\Carbon($tickets_logs[$i - 1]['time_stamp']))->diffInMinutes((new Carbon\Carbon($ticket_log['time_stamp']))) }}
#else
-
#endif
</td>
</tr>
#endforeach
</tbody>
</table>

What are the currently supported CSS selectors available to VBA?

Back on May 19th 2021, I wrote this Q&A regarding recent (Apr-May-21) suspected changes to an interface in relation to mshtml.dll and late bound referencing. This is a part 2, if you will.
Previously, in questions such as this and this, I have remarked upon the lack of support for various CSS selectors with mshtml.dll, in particular regarding pseudo-classes. In the aforementioned questions, I highlighted that nth-child() and nth-of-type() were not implemented with respect to MSHTML.
Typically, as demonstrated here, not supported selector syntax can result in:
Run-time error '-2140143604 (8070000c)': Could not complete the
operation due to error 8070000c.
I expect some things to break as various versions/platforms are no longer supported in relation to Internet Explorer (IE) (which MSHTML is related to - see my this. What I did not expect
to find was a recent improvement in supported CSS selectors. Take the following example:
Option Explicit
''Required references:
'' Microsoft HTML Object Library
Public Sub CssTest()
Const URL = "https://books.toscrape.com/"
Dim html As MSHTML.HTMLDocument
Set html = New MSHTML.HTMLDocument
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", URL, False
.send
html.body.innerHTML = .responseText
End With
Debug.Print html.querySelector("meta:nth-of-type(2)").outerHTML
End Sub
Prior to Apr-May'21, this would have errored out due to the use of non-implemented syntax.
Now, on my set-up, where I saw an update to mshtml.dll during early May (latest), I get the same result as had I run this via an automated Internet Explorer instance, where it was already supported:
<meta name="created" content="24th Jun 2016 09:29">
So, what are the currently supported CSS selectors available to VBA?
I have covered the 'why do we care?' in the previous Q&A so won't repeat here. I will however, re-state my set-up:
My set-up:
OS Name Microsoft Windows 10 Pro
Version 10.0.19042 Build 19042
System Type x64-based PC
Microsoft® Excel® 2019 MSO (16.0.13929.20206) 32-bit (Microsoft Office Professional Plus)
Version 2104 Build 13929.20373
mshtml.dll file 11.00.19041.985
ieframe.dll file 11.0.19041.964
Feedback:
As with the prior Q&A, any feedback on set-ups which do/do not see these changes I would appreciate. I will add feedback to this for others to be able to reference.
tl;dr;
There is much greater support for css selectors and for Element.querySelector (allowing for greater flexibility in chaining querySelector(All) calls. This enormously enhances the expressivity of the MSHTML class, in terms of CSS selectors, and brings it on par with Selenium Basic.
Motivation:
I have been wanting to write a list of supported selectors for some time, due to the lack of documentation on this in relation to VBA, and the trial and error nature of learning what does and doesn't work. This latest change has spurred me to do so, and include those libraries which currently support use of CSS selectors within them.
CAVEATS:
This is not exhaustive; it is pretty comprehensive.
Should you find any errors, particularly with respect to Selenium Basic, which I had to write from memory, please notify me and I will edit accordingly.
The recent changes, represented by shaded cells within the summary table (JSFiddle)| marked with ✔* , within simplified table below, are as they pertain to my set-up, at this point in time. Your mileage may vary e.g. CSS selectors were not supported at all < IE8.
Before and After:
Traditionally, the expressivity of CSS selectors within VBA was as follows, with respect to the libraries supporting them:
Selenium implementing, by far, the most CSS selectors.
Current state:
The current state of implemented selectors I believe to be as follows (sorry for image quality, even when you click to enlarge table - please see JSFiddle for clearest table view):
I include this as a simplified HTML insert as well, so you can click on hyperlinks. Please click the Run code snippet below the code insert, then the Full page link. Apologies, the table is large and I haven't even covered all conceivable selectors - only the main ones I consider likely to be frequently of use. Inserting a fancy table threw me over the body character limit so here we are. For a fancy table please see this JSFiddle - the newly supported are shaded.
<!DOCTYPE html>
<html>
<head>
<title>VBA: Valid CSS Selectors 2021-05-30</title>
</head>
<body>
<h1>VBA: Valid CSS Selectors 2021-05-30</h1>
<table>
<tr>
<td colspan="2">
Selectors Level 3 Specification
</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Pattern</td>
<td>Represents</td>
<td>Description</td>
<td>Level</td>
<td>Microsoft HTML Object Library (MSHTML)</td>
<td>Microsoft Internet Explorer Controls (SHDocVw)</td>
<td>Selenium Type Library (Selenium)</td>
<td>Remarks</td>
</tr>
<tr>
<td>*</td>
<td>any element</td>
<td>
Universal selector
</td>
<td>2</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E</td>
<td>an element of type E</td>
<td>
Type selector
</td>
<td>1</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E[foo]</td>
<td>an E element with a "foo" attribute</td>
<td>
Attribute selectors
</td>
<td>2</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E[foo="bar"]</td>
<td>an E element whose "foo" attribute value is exactly equal to "bar"</td>
<td>
Attribute selectors
</td>
<td>2</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E[foo~="bar"]</td>
<td>an E element whose "foo" attribute value is a list of whitespace-separated values, one of which is exactly equal to "bar"</td>
<td>
Attribute selectors
</td>
<td>2</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E[foo^="bar"]</td>
<td>an E element whose "foo" attribute value begins exactly with the string "bar"</td>
<td>
Attribute selectors
</td>
<td>3</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E[foo$="bar"]</td>
<td>an E element whose "foo" attribute value ends exactly with the string "bar"</td>
<td>
Attribute selectors
</td>
<td>3</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E[foo*="bar"]</td>
<td>an E element whose "foo" attribute value contains the substring "bar"</td>
<td>
Attribute selectors
</td>
<td>3</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E[foo|="en"]</td>
<td>an E element whose "foo" attribute has a hyphen-separated list of values beginning (from the left) with "en"</td>
<td>
Attribute selectors
</td>
<td>2</td>
<td>x</td>
<td>x</td>
<td>x</td>
<td> </td>
</tr>
<tr>
<td>E[attr operator value i]</td>
<td>value compared case-insensitively (ASCII range).</td>
<td>
Attribute selectors
</td>
<td>4</td>
<td>x</td>
<td>x</td>
<td>?</td>
<td>
i identifier
</td>
</tr>
<tr>
<td>E[attr operator value s]</td>
<td>value compared case-sensitively (ASCII range).</td>
<td>
Attribute selectors
</td>
<td>4</td>
<td>x</td>
<td>x</td>
<td>x</td>
<td>
s identifier
</td>
</tr>
<tr>
<td>E:root</td>
<td>an E element, root of the document</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td>HTML node only</td>
</tr>
<tr>
<td>E:nth-child(n)</td>
<td>an E element, the n-th child of its parent</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td>nth-child(odd) and (even) as well as nth-child(range) also supported</td>
</tr>
<tr>
<td>E:nth-last-child(n)</td>
<td>an E element, the n-th child of its parent, counting from the last one</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:nth-of-type(n)</td>
<td>an E element, the n-th sibling of its type</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:nth-last-of-type(n)</td>
<td>an E element, the n-th sibling of its type, counting from the last one</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:first-child</td>
<td>an E element, first child of its parent</td>
<td>
Structural pseudo-classes
</td>
<td>2</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:last-child</td>
<td>an E element, last child of its parent</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:first-of-type</td>
<td>an E element, first sibling of its type</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:last-of-type</td>
<td>an E element, last sibling of its type</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:only-child</td>
<td>an E element, only child of its parent</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:only-of-type</td>
<td>an E element, only sibling of its type</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:empty</td>
<td>an E element that has no children (including text nodes)</td>
<td>
Structural pseudo-classes
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:link</td>
<td rowspan="2">an E element being the source anchor of a hyperlink of which the target is not yet visited (:link) or already visited (:visited)</td>
<td rowspan="2">
The link pseudo-classes
</td>
<td>1</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:visited</td>
<td>1</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E:not(s)</td>
<td>an E element that does not match simple selector s</td>
<td>
Negation pseudo-class
</td>
<td>3</td>
<td>✔*</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E F</td>
<td>an F element descendant of an E element</td>
<td>
Descendant combinator
</td>
<td>1</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E > F</td>
<td>an F element child of an E element</td>
<td>
Child combinator
</td>
<td>2</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E + F</td>
<td>an F element immediately preceded by an E element</td>
<td>
Next-sibling combinator
</td>
<td>2</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>E ~ F</td>
<td>an F element preceded by an E element</td>
<td>
Subsequent-sibling combinator
</td>
<td>3</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td>foo, bar</td>
<td>foo, bar will match both <foo> and <bar> elements.</td>
<td>
Selector list
</td>
<td>1</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td> </td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>element.querySelector</td>
<td>Expanded element.querySelector</td>
<td>
Element.querySelector
</td>
<td>API</td>
<td>✔</td>
<td>✔</td>
<td>✔</td>
<td>Can now chain querySelector(All) calls on wider base node range</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Lib info:</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>Microsoft HTML Object Library (MSHTML)</td>
<td>MS Internet Explorer Controls (SHDocVw)</td>
<td>Selenium Type Library (Chromedriver)</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Lib</td>
<td>mshtml.dll</td>
<td>ieframe.dll</td>
<td>selenium.dll</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>File Version</td>
<td>11.00.19041.985</td>
<td>11.0.19041.964</td>
<td>2.0.9.0</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Date</td>
<td>2021-05-12</td>
<td>2021-05-12</td>
<td>2016-03-02</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</body>
</html>
12 newly supported pseudo-classes and an expanded Element.querySelector:
If you run the above snippet, and view full page, you will see there are now, at least, 12 newly supported pseudo-classes supported, as well as mention of expanded Element.querySelector. Bam, kapow, ker-sploosh, shut the proverbial front door ... welcome to VBA CSS Canaan, Scraper's Shangri-la, Nerd Nirvana!
I think there may also have been interesting updates to ieframe.dll; the focus here is on recent mshtml.dll changes. You may wish to review the IE support under the Lifecyle announcements here and here, or search for Lifecycle FAQ - Internet Explorer and Microsoft Edge.
As the benefit of the expanded Element.querySelector() was not covered in the last Q&A, I will briefly mention it here. By expanded, I mean an increased number of elements which you can call querySelector on, such that you can chain .querySelector() i.e .querySelector(..).querySelector(..) and .querySelector(..).querySelectorAll(..).
Previously, this was largely not possible. As exemplified by this question. Typically, the workaround was to chain traditional methods onto the returned node e.g.
html.querySelector("body").getElementsByTagName("li"); this led to unsightly chaining and hard to follow, as well as limited, paths to target elements. Better, IMHO, was the idea of a surrogate MSHTML.HTMLDocument variable, which would carry the innerHTML of the current node returned by querySelector, and thus allow you to call querySelector(All) again; and thereby gain access to much faster matching, clearer syntax and greater versatility. Numerous examples of that approach here.
End Notes:
This is a document under revision. All feedback on improvements welcomed.
Thanks:
Finally, a big thanks to #SIM for running a test script of mine to examine this on a different set-up.

rowSpan hides rows

<table>
<tr> <td rowspan="2">1</td> <td>2</td> </tr>
<tr> <td rowspan="2">3</td> </tr>
<tr> <td>4</td> </tr>
</table>
seemingly only displays two rows:
The reason for hiding the second row [1 3] is, that the cells with text 1 and 3 are reduced in height. Is there a way to ensure, that the second row is visible in the display (not only in DOM)?
The problem gets clearer, if you look at the same table with an additional column:
<table>
<tr> <td rowspan="2">1</td> <td>2</td> <td>0</td> </tr>
<tr> <td rowspan="2">3</td> <td>0</td> </tr>
<tr> <td>4</td> <td>0</td> </tr>
</table>
which is displayed like:
You can add a height property to the row:
<table border=1>
<tr>
<td rowspan="2">1</td>
<td>2</td>
</tr>
<tr style="height: 1.5em">
<td rowspan="2">3</td>
</tr>
<tr>
<td>4</td>
</tr>
</table>
One suboptimal option could be to add an empty column:
<table>
<tr> <td rowspan="2">1</td> <td>2</td> <td class="void"></td> </tr>
<tr> <td rowspan="2">3</td> <td class="void"></td> </tr>
<tr> <td>4</td> <td class="void"></td> </tr>
</table>
CSS:
table,td {border:1px solid}
.void {height:1em;padding:0;border:0}
However, the spacing between columns leads to unnecessary space for the added column:
As this problem could be solved with padding-left for TD and a cellspacing of 0 for the table, this solution would not be general enough, so I'm still waiting for a good idea.

Beautifulsoup replace colspan=2 with single col

I'm trying to parse data from rows which occasionally have a colspan=2 which spoils my ability to target data to extract.
What I'd like to do is remove the 'colspan=2' from the table element every time it occurs:
#replace
<td colspan="2" class="time">10:00 AM</td>
#with
<td>635</td>
Is this possible? And can I work it into a conditional if then else?
Here's a more verbose example:
<table>
<tr class="playerRow even">
<td class="pos">1</td>
<td><span class="rank"></span> -</td>
<td class="player"><p class="playerName">John doe</p></td>
<td class="background">X</td>
<td>345</td> #THIS ELEMENT FREQUENT
<td></td>
<td></td>
<td></td>
<td></td>
<td style=""></td>
</tr><
<tr class="playerRow odd">
<td class="pos">1</td>
<td><span class="rank"></span> -</td>
<td class="player"><p class="playerName">John doe</p></td>
<td class="background">X</td>
<td colspan="2" class="myClass" style="">3:15 PM</td> #THIS ELEMENT OCCASIONAL
<td></td>
<td></td>
<td></td>
<td></td>
<td style=""></td>
</tr>
<tr class="playerRow odd">
<td class="pos">1</td>
<td><span class="rank"></span> -</td>
<td class="player"><p class="playerName">John doe</p></td>
<td class="background">X</td>
<td>22</td> #THIS ELEMENT FREQUENT
<td></td>
<td></td>
<td></td>
<td></td>
<td style=""></td>
</tr>
</table>
So whenever I come across the colspan I'd like to replace it with a plain td, so it doesn't shunt the row elements across and mess up my count.
This will convert:
<td colspan="2" class="myClass" style="">3:15 PM</td>
to:
<td>3:15 PM</td>
from bs4 import BeautifulSoup
bs = BeautifulSoup(html)
for x in bs.findAll("td"):
if "colspan" in x.attrs:
x.attrs = {}
Do you want it to remove the value also?

Nested tables with related parent content

Having a semantics issue. I have a basic table with a standard header and footer. Each row contains an order, beneath each row I need to display another table, that will contain a break down of costs relating to that order. Additionally, these inner tables will be displayed with a jQuery accordion to hide and show when required (but I'm just concentrating on the HTML for now)
How can I semantically approach this in HTML?
<table>
<thead>
<th>Package number</th>
<th>Date placed</th>
<th>Placed by</th>
<th>Total cost</th>
</thead>
<tr>
<td>1</td>
<td>Weds</td>
<td>Jonno</td>
<td>£15</td>
</tr>
<tr>
<td colspan="4">
<table>
<thead>
<th>Part number</th>
<th>Description</th>
<th>Qty shipped</th>
<th>Weight</th>
</thead>
<tbody>
<td>18293</td>
<td>Blah blah blah</td>
<td>72</td>
<td>20Kg</td>
</tbody>
</table>
</td>
</tr>
<tr>
<td>2</td>
<td>Thurs</td>
<td>Jonno</td>
<td>£1</td>
</tr>
<tr>
<td>3</td>
<td>Fri</td>
<td>Jonno</td>
<td>£7</td>
</tr>
</table>
Here's a fiddle: http://jsfiddle.net/yuW7f/ - The problem here is that the row containing the inner table, is totally unrelated to the order row
If you are looking for a parent element you can use to group related rows, you can use <tbody> elements. A table can have multiple <tbody> elements:
<table>
<thead>
<tr>
<th>Package number</th>
<th>Date placed</th>
<th>Placed by</th>
<th>Total cost</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Weds</td>
<td>Jonno</td>
<td>£15</td>
</tr>
<tr>
<td colspan="4">
<table>
<thead>
<tr>
<th>Part number</th>
<th>Description</th>
<th>Qty shipped</th>
<th>Weight</th>
</tr>
</thead>
<tbody>
<tr>
<td>18293</td>
<td>Blah blah blah</td>
<td>72</td>
<td>20Kg</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
<tr>
<td>2</td>
<td>Thurs</td>
<td>Jonno</td>
<td>£1</td>
</tr>
<tr>
<td>3</td>
<td>Fri</td>
<td>Jonno</td>
<td>£7</td>
</tr>
</table>
Whether or not that makes your code more semantically correct is debatable. You could also give your rows classes to indicate whether the row is a summary row or a detail row, or attributes to indicate relationships to other rows. Semantically, it seems fine as it is to me.
By the way, you are missing some <tr> elements. A <tbody>, <thead>, or <tfoot> element does not replace a <tr> element.