{"id":2305,"date":"2023-04-21T17:41:35","date_gmt":"2023-04-21T17:41:35","guid":{"rendered":"https:\/\/morecpq.com\/?p=2305"},"modified":"2023-05-23T13:34:01","modified_gmt":"2023-05-23T17:34:01","slug":"html_to_xslfo","status":"publish","type":"post","link":"https:\/\/morecpq.com\/index.php\/2023\/04\/21\/html_to_xslfo\/","title":{"rendered":"Quote Templates &#8211; Custom Content &#8211; Lines Section &#8211; Rich Description &#8211; Error generating document: Bad Request"},"content":{"rendered":"\n<p>Error generating document: Bad Request is not the best message.  Sometimes it means you have a custom template content that&#8217;s blowing up.  One of the reasons this might be happening is that you are trying to output the description field for each line.  Well, that&#8217;s a bummer because the VF page for the custom content has to be in XSL:FO, not HTML.  But rich text fields are stored in HTML.  SO!  How do you get your rich text field to display in a custom content??  Two ways: either strip all HTML tags out of your rich text field&#8217;s value -OR- use the code below to translate your rich text HTML tags to XSL:FO!  Yep.  This translates most tags.  Leave a comment with any tags that aren&#8217;t translating!<\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-small-font-size\"><code>    public String htmlToFo(String html){\n        String output = '';\n        \n        if (html != null) {\n            System.debug('html: '+html);\n            DOM.Document doc = new DOM.Document();\n            Dom.Document newdoc = new DOM.Document();\n            \n            doc.load('&lt;block>'+html.replace('&lt;br>', '&lt;br \/>').replace('&amp;', '&amp;amp;')+'&lt;\/block>');\n            \n            Dom.XMLNode root = doc.getRootElement();\n            Dom.XMLNode newroot = newdoc.createRootElement('block', null, null);\n            \n            newroot = convertNodes(root.getChildren(), newroot, 0, '');\n            output = newdoc.toXmlString().replace('&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?>', '');\n            System.debug('output: '+output);\n        }\n        \n        return output;\n    }\n    \n    private Map&lt;Decimal, String> listBulletsByLevel = new Map&lt;Decimal, String>{\n        0 => '\u2022',\n        1 => '\u25e6',\n        2 => '\u25aa\ufe0e'\n    };\n    \n    private Dom.XMLNode convertNodes(List&lt;Dom.XMLNode> childrenToConvert, Dom.XMLNode newroot, Decimal listlevel, String listtype) {\n        if (newroot != null) {\n            Decimal orderedListCurrentItem = 1;\n            for(Dom.XMLNode child : childrenToConvert) {\n                Dom.XMLNode newchild = null;\n                if (child.getName() == 'br') {\n                    newchild = newroot.addChildElement('block', null, null);\n                    newchild.setAttribute('padding-top', '0pt');\n                    newchild.setAttribute('padding-bottom', '0pt');\n                    newchild.addTextNode(' ');\n                } else if (child.getName() == 'p') {\n                    newchild = newroot.addChildElement('block', null, null);\n                    newchild.setAttribute('padding-top', '10pt');\n                    newchild.setAttribute('padding-bottom', '4pt');\n                } else if (child.getName() == 'div') {\n                    newchild = newroot.addChildElement('block', null, null);\n                    newchild.setAttribute('padding-top', '0pt');\n                    newchild.setAttribute('padding-bottom', '0pt');\n                } else if (child.getName() == 'ul') {\n                    listtype='unordered';\n                    newchild = newroot.addChildElement('list-block', null, null);\n                    newchild.setAttribute('padding-top', '4pt');\n                } else if (child.getName() == 'ol') {\n                    orderedListCurrentItem = 1;\n                    listtype='ordered';\n                    newchild = newroot.addChildElement('list-block', null, null);\n                    newchild.setAttribute('padding-top', '4pt');\n                } else if (child.getName() == 'li') {\n                    newchild = newroot.addChildElement('list-item', null, null);\n                    Dom.XMLNode label = newchild.addChildElement('list-item-label', null, null);\n                    Decimal indent = listtype == 'unordered' ? 19 : 24;\n                    label.setAttribute('start-indent', (13+(listlevel*13))+'pt');\n                    if (listtype == 'unordered') {\n                        label.addChildElement('block', null, null).addTextNode((String)(listBulletsByLevel.get(0)));\/\/listlevel>2?0:listlevel)));\n                    } else {\n                        label.addChildElement('block', null, null).addTextNode(orderedListCurrentItem+'.');\n                    }\n                    Dom.XMLNode body = newchild.addChildElement('list-item-body', null, null);\n                    body.setAttribute('start-indent', (indent+(listlevel*13))+'pt');\n                    Dom.XMLNode bodytext = body.addChildElement('block', null, null);\n                    newchild = bodytext;\n                    listlevel++;\n                    orderedListCurrentItem++;\n                } else if (child.getName() == 'strong') {\n                    newchild = newroot.addChildElement('inline', null, null);\n                    newchild.setAttribute('font-weight', 'bold');\n                } else if (child.getName() == 'em' || child.getName() == 'i') {\n                    newchild = newroot.addChildElement('inline', null, null);\n                    newchild.setAttribute('font-style', 'italic');\n                } else if (child.getName() == 'u') {\n                    newchild = newroot.addChildElement('inline', null, null);\n                    newchild.setAttribute('text-decoration', 'underline');\n                } else if (child.getName() == 's') {\n                    newchild = newroot.addChildElement('inline', null, null);\n                    newchild.setAttribute('text-decoration', 'line-through');\n                } else if (child.getName() == 'sub') {\n                    newchild = newroot.addChildElement('inline', null, null);\n                    newchild.setAttribute('vertical-align', 'sub');\n                    newchild.setAttribute('font-size', '8pt');\n                } else if (child.getName() == 'sup') {\n                    newchild = newroot.addChildElement('inline', null, null);\n                    newchild.setAttribute('vertical-align', 'sup');\n                    newchild.setAttribute('font-size', '8pt');\n                } else if (child.getName() == 'blockquote') {\n                    newchild = newroot.addChildElement('block', null, null);\n                    newchild.setAttribute('start-indent', '13pt');\n                } else if (child.getName() == 'img') {\n                    newchild = newroot.addChildElement('external-graphic', null, null);\n                    if (child.getAttributeValue('width', null) != null &amp;&amp; child.getAttributeValue('width', null) != '') {\n                        newchild.setAttribute('content-width', child.getAttributeValue('width', null));\n                    }\n                    if (child.getAttributeValue('height', null) != null &amp;&amp; child.getAttributeValue('height', null) != '') {\n                    \tnewchild.setAttribute('content-height', child.getAttributeValue('height', null));\n                    }\n                    newchild.setAttribute('src', child.getAttributeValue('src', null));\n                } else if (child.getName() == 'a') {\n                    newchild = newroot.addChildElement('basic-link', null, null);\n                    newchild.setAttribute('color', 'blue');\n                    newchild.setAttribute('text-decoration', 'underline');\n                    newchild.setAttribute('external-destination', child.getAttributeValue('href', null));\n                } else {\n                    newchild = newroot.addChildElement('inline', null, null);\n                    newchild.addTextNode(child.getText());\n                }\n                if (child.getAttributeValue('style', null) != null &amp;&amp; child.getAttributeValue('style', null) != '') {\n                    String style = child.getAttributeValue('style', null);\n                    if (style.contains('background-color')) {\n\t\t\t\t\t\tPattern pat = Pattern.compile('.*?background-color:\\\\s*(&#91;^;]+).*?');\n                        Matcher match = pat.matcher(style);\n                        match.find();\n                        Integer groupsToCapture = match.groupCount();\n                        if (groupsToCapture > 0) {\n                            String bgcolor = match.group(1).replace(';', '');\n                            newchild.setAttribute('background-color', bgcolor);\n                        }\n                        style = style.replace('background-color', '');\n                    }\n                    if (style.contains('color')) {\n\t\t\t\t\t\tPattern pat = Pattern.compile('.*?color:\\\\s*(&#91;^;]+).*?');\n                        Matcher match = pat.matcher(style);\n                        match.find();\n                        Integer groupsToCapture = match.groupCount();\n                        if (groupsToCapture > 0) {\n                            String color = match.group(1).replace(';', '');\n                            newchild.setAttribute('color', color);\n                        }\n                    }\n                    if (style.contains('font-size')) {\n\t\t\t\t\t\tPattern pat = Pattern.compile('.*?font-size:\\\\s*(&#91;^;]+).*?');\n                        Matcher match = pat.matcher(style);\n                        match.find();\n                        Integer groupsToCapture = match.groupCount();\n                        if (groupsToCapture > 0) {\n                            String fontSize = match.group(1).replace(';', '');\n                            newchild.setAttribute('font-size', fontSize);\n                        }\n                    }\n                }\n                \n                \/\/ process any child elements of this element.\n                List&lt;Dom.XMLNode> grandkids = child.getChildren();\n                if (grandkids != null &amp;&amp; grandkids.size() > 0) {\n                    convertNodes(grandkids, newchild, listlevel, listtype);\n                }\n                \n                if (child.getName() == 'li') {\n                    listlevel--;\n                }\n            }\n        }\n        return newroot;\n    }\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Error generating document: Bad Request is not the best message. Sometimes it means you have a custom template content that&#8217;s blowing up. One of the reasons this might be happening is that you are trying to output the description field for each line. Well, that&#8217;s a bummer because the VF page for the custom content &hellip;<br \/><a href=\"https:\/\/morecpq.com\/index.php\/2023\/04\/21\/html_to_xslfo\/\" class=\"more-link pen_button pen_element_default pen_icon_arrow_double\">Continue reading <span class=\"screen-reader-text\">Quote Templates &#8211; Custom Content &#8211; Lines Section &#8211; Rich Description &#8211; Error generating document: Bad Request<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2305","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_featured_media_url":"","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/posts\/2305","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/comments?post=2305"}],"version-history":[{"count":21,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/posts\/2305\/revisions"}],"predecessor-version":[{"id":2368,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/posts\/2305\/revisions\/2368"}],"wp:attachment":[{"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/media?parent=2305"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/categories?post=2305"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/morecpq.com\/index.php\/wp-json\/wp\/v2\/tags?post=2305"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}