{"id":157,"date":"2011-02-02T14:28:37","date_gmt":"2011-02-02T14:28:37","guid":{"rendered":"http:\/\/www.ericwhite.com\/home2\/bm8qcmjy\/public_html\/blog\/?p=157"},"modified":"2011-02-04T15:32:11","modified_gmt":"2011-02-04T15:32:11","slug":"more-enhancements-to-the-document-template","status":"publish","type":"post","link":"https:\/\/www.ericwhite.com\/blog\/2011\/02\/02\/more-enhancements-to-the-document-template\/","title":{"rendered":"More Enhancements to the Document Template"},"content":{"rendered":"<p>The next step in building this document generation system is to define a few content controls that allow the template designer to write other necessary C# code for the document generation process.\u00a0 As an example, the template designer needs to write code that executes when the document generation process starts, i.e. the code that will go in Main.\u00a0 There is other code the template designer needs to write \u2013 details below.<\/p>\n<p>This post is the fourth in a series of blog posts. Here is the complete list: <a href=\"https:\/\/www.ericwhite.com\/blog\/map\/generating-open-xml-wordprocessingml-documents-blog-post-series\/\">Generating Open XML WordprocessingML Documents Blog Post Series<\/a><\/p>\n<p>For this particular approach to building a document generation system, I am planning on the following:<\/p>\n<ul>\n<li>The document generation process will first process the document template and <strong>generate a new C# program<\/strong>.<\/li>\n<li>After generating the new program, the document generation process will <strong>compile the new program, and then run it<\/strong>, which will then generate all documents for this document generation run.<\/li>\n<li>There are, of course, pros and cons to this approach. I\u2019ll mention some of them as I go along.<\/li>\n<\/ul>\n<p>The generated code will be a combination of:<\/p>\n<ul>\n<li>Code to create the Open XML SDK package, and to create an in-memory clone of the template document.<\/li>\n<li>LINQ to XML code to update the contents of the main document part in the package. I\u2019ll have more to say about this in the next post. I\u2019m going to write a pure functional transformation from am XML tree to C# code to create the tree. The generated code will use functional construction, not a DOM style approach.<\/li>\n<li>Code extracted from the template document and inserted at appropriate places so that it generates the proper WordprocessingML markup. The code to extract the content of the content controls, and include the content control code in the appropriate places. This will be just a few lines of code.<\/li>\n<\/ul>\n<p>This sounds more complicated than it is. In upcoming posts, I\u2019ll walk through how the code works in detail.\u00a0 Also, when completed, this example will be super-easy to run.\u00a0 It will be educational to play around with code in the content controls to generate a wide variety of documents.<\/p>\n<p>I have further refined the C# code that the template designer will write inside of content controls. In addition to that refinement, I have added four more content controls where it doesn\u2019t matter where the template designer places them in the document. These content controls contain code that we need to make the process work \u2013 they don\u2019t contain code directly associated with generating content.<\/p>\n<h1>The Generated Program Structure<\/h1>\n<p>Before discussing the code in the various content controls, I want to discuss the structure of the generated program. There will be a class named <strong>Generator<\/strong>, which will be generated in the code generation process. This class will have a couple of properties or fields, and will have one method (beyond the constructor). There will one instance of this class for each generated document.<\/p>\n<p>The code in the <strong>Value<\/strong>, <strong>Table<\/strong>, and <strong>Conditional<\/strong> content controls executes in the context of an instance of the <strong>Generator<\/strong> class. Therefore, the code can access instance fields and properties.<\/p>\n<h1>New Version of the Template Document<\/h1>\n<p>First, I\u2019ll examine the new version of the template document. The titles of the content controls are the same, but the code inside is different from the last post. As before, there are the <strong>Value <\/strong>content controls that contain values to be inserted into the document.\u00a0 I agree with <a href=\"https:\/\/www.ericwhite.com\/blog\/2011\/01\/28\/the-second-iteration-of-the-template-document\/#comments\">feedback that Svetlin provided<\/a> \u2013 the value derived from this content control will use the formatting of the underlying run or paragraph.\u00a0 No need to specify a style.<\/p>\n<p>The following code accesses an instance property of the <strong>Generator<\/strong> class.\u00a0 The instance property is <strong>Cust<\/strong>.<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image5.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"image\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image_thumb5.png\" border=\"0\" alt=\"image\" width=\"679\" height=\"153\" \/><\/a><\/p>\n<p>The <strong>Table<\/strong> content control looks about the same as in the last post, except that it is now written to access fields in the <strong>Generator<\/strong> object:<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image6.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"image\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image_thumb6.png\" border=\"0\" alt=\"image\" width=\"682\" height=\"309\" \/><\/a><\/p>\n<p>Same thing with <strong>Conditional<\/strong> \u2013 it can access the <strong>Cust<\/strong> instance property.<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image7.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"image\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image_thumb7.png\" border=\"0\" alt=\"image\" width=\"656\" height=\"139\" \/><\/a><\/p>\n<p>The design of the <strong>Ask<\/strong> content control is the same as in the last iteration of this template document:<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image8.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"image\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image_thumb8.png\" border=\"0\" alt=\"image\" width=\"509\" height=\"99\" \/><\/a><\/p>\n<p>There are four new content controls in this template that enable the template designer to write the necessary code so that the document generation process can generate a C# program that is complete and can compile:<\/p>\n<ul>\n<li>Using<\/li>\n<li>Classes<\/li>\n<li>GeneratorMembers<\/li>\n<li>GeneratorMain<\/li>\n<\/ul>\n<p>The <strong>Using <\/strong>content control contains the <strong>using <\/strong>statements for the generated program. The generated program may be so simple that it only uses LINQ to XML, as in the example I\u2019m working up. However, it could be more interesting \u2013 it might access an OData feed. It might connect to any arbitrary database or web service. It can connect to any data source that you can get to with .NET. Therefore, we need the ability to specify the <strong>using <\/strong>statements for the generated program:<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image9.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"image\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image_thumb9.png\" border=\"0\" alt=\"image\" width=\"365\" height=\"168\" \/><\/a><\/p>\n<p>The <strong>Classes<\/strong> content control enables the template designer to define some classes that contain the data that the program reads from the data source.\u00a0 In this first example, there is a <strong>Customer <\/strong>class and an <strong>Order <\/strong>class:<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image10.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"image\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image_thumb10.png\" border=\"0\" alt=\"image\" width=\"412\" height=\"312\" \/><\/a><\/p>\n<p>The <strong>GeneratorMembers <\/strong>content control enables the template designer to specify members of the <strong>Generator <\/strong>class.\u00a0 This field contains the customer that a particular <strong>Generator <\/strong>object is generating a document for.<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image11.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"image\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image_thumb11.png\" border=\"0\" alt=\"image\" width=\"249\" height=\"94\" \/><\/a><\/p>\n<p>Last, but not least, there will be the <strong>GeneratorMain <\/strong>content control, which contains the code that will go in the <strong>Main <\/strong>method in the generated program:<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image12.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"image\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image_thumb12.png\" border=\"0\" alt=\"image\" width=\"656\" height=\"499\" \/><\/a><\/p>\n<p>This <strong>GeneratorMain <\/strong>is expecting to read an XML document that looks like this:<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image13.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"image\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/image_thumb13.png\" border=\"0\" alt=\"image\" width=\"484\" height=\"660\" \/><\/a><\/p>\n<p>And the generated program, after everything is said and done, will look something like this:<br \/>\n<code><br \/>\nusing&nbsp;System;<br \/>\nusing&nbsp;System.Collections.Generic;<br \/>\nusing&nbsp;System.Linq;<br \/>\nusing&nbsp;System.Text;<br \/>\nusing&nbsp;System.Xml.Linq;<\/p>\n<p>namespace&nbsp;DocumentGenerator<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;Customer<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;int&nbsp;CustomerID;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;string&nbsp;Name;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;bool&nbsp;IsHighValueCustomer;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;Order<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;int&nbsp;CustomerID;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;string&nbsp;ProductDescription;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;decimal&nbsp;Quantity;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;DateTime&nbsp;OrderDate;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;Generator<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Customer&nbsp;Cust;<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;GenerateDocument()<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/&nbsp;This&nbsp;method&nbsp;will&nbsp;be&nbsp;automatically&nbsp;generated&nbsp;during&nbsp;the&nbsp;generation&nbsp;process.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/&nbsp;There&nbsp;will&nbsp;be&nbsp;a&nbsp;lot&nbsp;of&nbsp;code&nbsp;in&nbsp;this&nbsp;method.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(\"Generating&nbsp;document&nbsp;for&nbsp;customer&nbsp;{0}\",&nbsp;Cust.CustomerID);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;void&nbsp;Main(string[]&nbsp;args)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XElement&nbsp;data&nbsp;=&nbsp;XElement.Load(\"Data.xml\");<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;customers&nbsp;=&nbsp;data<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Elements(\"Customers\")<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Elements(\"Customer\")<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(c&nbsp;=>&nbsp;new&nbsp;Customer()&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CustomerID&nbsp;=&nbsp;(int)c.Element(\"CustomerID\"),<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name&nbsp;=&nbsp;(string)c.Element(\"Name\"),<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IsHighValueCustomer&nbsp;=&nbsp;(bool)c.Element(\"IsHighValueCustomer\"),<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;orders&nbsp;=&nbsp;data<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Elements(\"Orders\")<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Elements(\"Order\")<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(o&nbsp;=>&nbsp;new&nbsp;Order()&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CustomerID&nbsp;=&nbsp;(int)o.Element(\"CustomerID\"),<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProductDescription&nbsp;=&nbsp;(string)o.Element(\"ProductDescription\"),<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Quantity&nbsp;=&nbsp;(decimal)o.Element(\"Quantity\"),<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OrderDate&nbsp;=&nbsp;(DateTime)o.Element(\"OrderDate\"),<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Generator&nbsp;p&nbsp;=&nbsp;new&nbsp;Generator();<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(var&nbsp;customer&nbsp;in&nbsp;customers)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.Cust&nbsp;=&nbsp;customer;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.GenerateDocument();<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>\n}<\/code><br \/>\nIn the next blog post, I\u2019m going to discuss generating C# code from an XML tree.\u00a0 This code needs to use functional construction, so that the code generation process can insert queries at all appropriate points in the generated code.\u00a0 That is going to be fun code to write!!!<\/p>\n<p><img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" style=\"border-style: none;\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/wlEmoticon-smile.png\" alt=\"Smile\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Discusses enhancments that enable the template designer to write infrastructure code for the document generation process.  Also discusses how the document generation process will work.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"_s2mail":"","footnotes":""},"categories":[7,3,5],"tags":[],"class_list":["post-157","post","type-post","status-publish","format-standard","hentry","category-document-generation-series","category-open-xml","category-wordprocessingml"],"_links":{"self":[{"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/posts\/157","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/comments?post=157"}],"version-history":[{"count":9,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/posts\/157\/revisions"}],"predecessor-version":[{"id":186,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/posts\/157\/revisions\/186"}],"wp:attachment":[{"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/media?parent=157"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/categories?post=157"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/tags?post=157"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}