How to add tags to a blog post in IBM Connections - blogs

How can I add tags to a blog post in IBM Connections? The API documentation says I need to update the blog post with a PUT command. If I do so according to the documentation, then I get a 500 Internal Server error as response. Same happens when trying to create a blog post with a POST command.
Question 1: what is wrong with the command?
Question 2: is there a way to only add tags without updating the content of the blog post?
sUrl = "https://my-connect-server/blogs/%BLOGID%/api/entries/%POSTID%"
sBody = "<?xml version=""1.0"" encoding=""UTF-8""?>" & _
"<entry xmlns=""http://www.w3.org/2005/Atom"">" & _
"<id>urn:lsid:ibm.com:blogs:entry-%POSTID%</id>" & _
"<title type=""text"">Test Blog Post</title>" & _
"<summary type=""html"">new summary</summary>" & _
"<content type=""html"">new content </content>" & _
"<category term=""new-tag-1""></category>" & _
"<category term=""new-tag-2""></category>" & _
"<entry>"
Call oHttp.Open("PUT", sUrl, False)
Call oHttp.setRequestHeader("Content-Type", "application/atom+xml")
Call oHttp.send(sBody)

The reason is you are not sending a full payload to the blog api. You should send back the full Blog entry with the additions/subtractions you want to make to the XML payload.
I call the api
https://<SERVER>/blogs/5133e363-7456-4525-afe6-188960888b35/api/entries/b17182a4-7807-4adf-97c7-8ac051a3f115
I had to trim off the XML header, so it's like this:
<entry xml:lang="en" dir="ltr" xmlns="http://www.w3.org/2005/Atom">
<id>urn:lsid:ibm.com:blogs:entry-b17182a4-7807-4adf-97c7-8ac051a3f115</id>
<snx:communityUuid xmlns:snx="http://www.ibm.com/xmlns/prod/sn">5133e363-7456-4525-afe6-188960888b35</snx:communityUuid>
<link href="https://<SERVER>:443/blogs/5133e363-7456-4525-afe6-188960888b35/api/entries/b17182a4-7807-4adf-97c7-8ac051a3f115" rel="edit" type="application/atom+xml">
</link>
<link href="https://<SERVER>/blogs/5133e363-7456-4525-afe6-188960888b35/entry/Test" rel="alternate" type="text/html">
</link>
<link href="https://<SERVER>:443/blogs/5133e363-7456-4525-afe6-188960888b35/feed/entrycomments/Test/atom" rel="replies" type="application/atom+xml" thr:count="0" xmlns:thr="http://purl.org/syndication/thread/1.0">
</link>
<app:collection href="https://<SERVER>:443/blogs/5133e363-7456-4525-afe6-188960888b35/api/recommend/entries/b17182a4-7807-4adf-97c7-8ac051a3f115" xmlns:app="http://www.w3.org/2007/app">
<atom:title xmlns:atom="http://www.w3.org/2005/Atom">Likes</atom:title>
<atom:category term="recommend" scheme="http://www.ibm.com/xmlns/prod/sn/collection" xmlns:atom="http://www.w3.org/2005/Atom">
</atom:category>
<app:categories fixed="yes">
</app:categories>
</app:collection>
<app:collection href="https://<SERVER>:443/blogs/5133e363-7456-4525-afe6-188960888b35/api/entrycomments/b17182a4-7807-4adf-97c7-8ac051a3f115" xmlns:app="http://www.w3.org/2007/app">
<atom:title xmlns:atom="http://www.w3.org/2005/Atom">Comment Entries</atom:title>
<app:accept>application/atom+xml;type=entry</app:accept>
<atom:category term="comments" scheme="http://www.ibm.com/xmlns/prod/sn/collection" xmlns:atom="http://www.w3.org/2005/Atom">
</atom:category>
<app:categories fixed="yes">
</app:categories>
</app:collection>
<snx:moderation status="approved" xmlns:snx="http://www.ibm.com/xmlns/prod/sn">
</snx:moderation>
<title type="text">Test</title>
<updated>2015-08-14T11:58:05.000Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2015-08-14T11:58:05.000Z</app:edited>
<published>2015-08-14T11:57:44.000Z</published>
<snx:rank scheme="http://www.ibm.com/xmlns/prod/sn/recommendations" xmlns:snx="http://www.ibm.com/xmlns/prod/sn">0</snx:rank>
<snx:rank scheme="http://www.ibm.com/xmlns/prod/sn/comment" xmlns:snx="http://www.ibm.com/xmlns/prod/sn">0</snx:rank>
<snx:rank scheme="http://www.ibm.com/xmlns/prod/sn/hit" xmlns:snx="http://www.ibm.com/xmlns/prod/sn">8</snx:rank>
<author>
<name>John Doe0</name>
<snx:userid xmlns:snx="http://www.ibm.com/xmlns/prod/sn">20000395</snx:userid>
<snx:userState xmlns:snx="http://www.ibm.com/xmlns/prod/sn">active</snx:userState>
<snx:isExternal xmlns:snx="http://www.ibm.com/xmlns/prod/sn">false</snx:isExternal>
</author>
<contributor>
<name>John Doe0</name>
<snx:userid xmlns:snx="http://www.ibm.com/xmlns/prod/sn">20000395</snx:userid>
<snx:userState xmlns:snx="http://www.ibm.com/xmlns/prod/sn">active</snx:userState>
<snx:isExternal xmlns:snx="http://www.ibm.com/xmlns/prod/sn">false</snx:isExternal>
</contributor>
<category term="test">
</category>
<category term="test2">
</category>
<app:control xmlns:app="http://www.w3.org/2007/app">
<app:draft>no</app:draft>
<snx:comments enabled="yes" days="0" xmlns:snx="http://www.ibm.com/xmlns/prod/sn">
</snx:comments>
</app:control>
<summary type="html"><p dir="ltr">Test</p></summary>
<content type="html"><p dir="ltr">Test</p></content>
</entry>
I added to the category tag before
<category term="test2">
</category>
I send a put to the same api as above, with header Content-Type: application/atom+xml and Method: PUT
You should get Status Code: 200 OK

Related

cts:near-query Marklogic on json documents

I am using search:search like below
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
let $options :=
<options xmlns="http://marklogic.com/appservices/search">
<concurrency-level>8</concurrency-level>
<search-option>unfiltered</search-option>
<transform-results apply="empty-snippet">
<!-- #apply=snippet : to get snippet-->
<per-match-tokens>30</per-match-tokens>
<max-matches>4</max-matches>
<max-snippet-chars>200</max-snippet-chars>
<preferred-matches/>
</transform-results>
<term>
<term-option>case-insensitive</term-option>
<term-option>wildcarded</term-option>
<term-option>stemmed</term-option>
<term-option>diacritic-insensitive</term-option>
<term-option>punctuation-insensitive</term-option>
</term>
<constraint name="title">
<range collation="http://marklogic.com/collation/codepoint" type="xs:string" facet="false">
<json-property>title</json-property>
</range>
</constraint>
<extract-document-data>
<!-- Full Title -->
<extract-path>/title</extract-path>
</extract-document-data>
<additional-query>
<cts:near-query distance="1" xmlns:cts="http://marklogic.com/cts">
<cts:json-property-word-query>
<cts:property>title</cts:property>
<cts:text xml:lang="en">chemotherapy</cts:text>
<cts:option>case-insensitive</cts:option>
</cts:json-property-word-query>
<cts:json-property-word-query>
<cts:property>title</cts:property>
<cts:text xml:lang="en">hospital</cts:text>
<cts:option>case-insensitive</cts:option>
</cts:json-property-word-query>
<cts:option>ordered</cts:option>
</cts:near-query>
</additional-query>
<additional-query/>
</options>
return
search:search('', $query, 1, 10)
Using this query I am getting the document with title, in the query distance between chemotherapy and hospital in 1
Result with title :{"title":"chemotherapy for cancer patients in the hospital."}
Am I doing something wrong?
Thanks
It worked after enabling the word position index in Db settings

Amazon Product API: Offers from Amazon missing

I am confused how the Amazon Product API works. For my example I used this ASIN (B00Y9S4V22) which is available in the german Amazon.
I requested the data from the API with the response Group "Large,OfferFull,Offers" and was confused because the only price it returns me is "1,80". On the Amazon Page itself it shows 2,37 (orderable with Prime).
As you can see in the response below it says that there are total 3 new (In the Summary in TotalNew) - which is correct. But in the Offer Listing I only have 1 of them - the cheapest. But my goal is to get the offer which is sold by Amazon it self / prime orderable / plus-product orderable. But these offers are missing completely.
When I open the "All Offers" link I get this result:
As you can see the amazon offer is listed there - but still missing in my response.
XML Response (I removed unnecessary properties)
<Items>
<Request>
<IsValid>True</IsValid>
<ItemLookupRequest>
<Condition>All</Condition>
<IdType>ASIN</IdType>
<ItemId>B00Y9S4V22</ItemId>
<ResponseGroup>Large</ResponseGroup>
<ResponseGroup>OfferFull</ResponseGroup>
<ResponseGroup>Offers</ResponseGroup>
<VariationPage>All</VariationPage>
</ItemLookupRequest>
</Request>
<Item>
<ASIN>B00Y9S4V22</ASIN>
<ParentASIN>B01HU1G8A2</ParentASIN>
<DetailPageURL>https://www.amazon.de/Westcott-00-Geodreieck-bruchsicher-transparent/dp/B00Y9S4V22?psc=1&SubscriptionId=AKIAJAD2WJOOQC6SJGWQ&tag=cheepah-21&linkCode=xm2&camp=2025&creative=165953&creativeASIN=B00Y9S4V22</DetailPageURL>
<SalesRank>832</SalesRank>
<ItemAttributes>
<ListPrice>
<Amount>237</Amount>
<CurrencyCode>EUR</CurrencyCode>
<FormattedPrice>EUR 2,37</FormattedPrice>
</ListPrice>
</ItemAttributes>
<OfferSummary>
<LowestNewPrice>
<Amount>180</Amount>
<CurrencyCode>EUR</CurrencyCode>
<FormattedPrice>EUR 1,80</FormattedPrice>
</LowestNewPrice>
<TotalNew>3</TotalNew>
<TotalUsed>0</TotalUsed>
<TotalCollectible>0</TotalCollectible>
<TotalRefurbished>0</TotalRefurbished>
</OfferSummary>
<Offers>
<TotalOffers>1</TotalOffers>
<TotalOfferPages>1</TotalOfferPages>
<MoreOffersUrl>https://www.amazon.de/gp/offer-listing/B00Y9S4V22?SubscriptionId=AKIAJAD2WJOOQC6SJGWQ&tag=cheepah-21&linkCode=xm2&camp=2025&creative=12738&creativeASIN=B00Y9S4V22</MoreOffersUrl>
<Offer>
<Merchant>
<Name>mane Büroshop</Name>
</Merchant>
<OfferAttributes>
<Condition>New</Condition>
</OfferAttributes>
<OfferListing>
<OfferListingId>47YkU0Y7wnSskg8Uv7WqMgMXIxp3CsbATIFxuhiVJN3WRBaDRBRVgDtK4OIpe%2ByOIQQubWu4jlopsbF3uBH2AeWqyOFDpEGOLh7X%2BPjKwYsRTKgA7vy12yfzZyVVIY%2F10%2BrPSNeI24F8fo9qxj%2FLCgUdrVCFhI2a</OfferListingId>
<Price>
<Amount>180</Amount>
<CurrencyCode>EUR</CurrencyCode>
<FormattedPrice>EUR 1,80</FormattedPrice>
</Price>
<AmountSaved>
<Amount>57</Amount>
<CurrencyCode>EUR</CurrencyCode>
<FormattedPrice>EUR 0,57</FormattedPrice>
</AmountSaved>
<PercentageSaved>24</PercentageSaved>
<Availability>Versandfertig in 1 - 2 Werktagen</Availability>
<AvailabilityAttributes>
<AvailabilityType>now</AvailabilityType>
<MinimumHours>24</MinimumHours>
<MaximumHours>48</MaximumHours>
</AvailabilityAttributes>
<IsEligibleForSuperSaverShipping>0</IsEligibleForSuperSaverShipping>
<IsEligibleForPrime>0</IsEligibleForPrime>
</OfferListing>
</Offer>
</Offers>
</Item>
</Items>
And here is the Request:
<Arguments>
<Argument Name="AWSAccessKeyId" Value="---"></Argument>
<Argument Name="AssociateTag" Value="---"></Argument>
<Argument Name="Condition" Value="All"></Argument>
<Argument Name="IdType" Value="ASIN"></Argument>
<Argument Name="ItemId" Value="B00Y9S4V22"></Argument>
<Argument Name="Operation" Value="ItemLookup"></Argument>
<Argument Name="ResponseGroup" Value="Large,OfferFull,Offers"></Argument>
<Argument Name="Service" Value="AWSECommerceService"></Argument>
<Argument Name="Timestamp" Value="2018-10-30T22:14:08.000Z"></Argument>
</Arguments>
I know that there is a "ListPrice" but as far as I understand Amazon this is not always the price which is Amazon is selling it.
For anyone else who is looking for a solution:
You can also provide the argument "MerchantId" and set it to "Amazon". I am still confused why not all Offers are listed but when setting the argument "MerchantId" the response will provide the Amazon Offer (but no offer else)

gContact namespace not working

I am trying to POST contact data to GContact to create a new contact. I can create a new contact if I use only "gd" XML elements, but when I try and post a "gContact" element it gives me an error. I'm sure it's something simple because I am a total amateur, but I would appreciate any help.
This works
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005">
<atom:category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/contact/2008#contact" />
<gd:name>
<gd:givenName>Jack</gd:givenName>
<gd:familyName>Masters</gd:familyName>
<gd:fullName>Jack Masters</gd:fullName>
<gd:additionalName>Rascal</gd:additionalName>
<gd:namePrefix>Sir</gd:namePrefix>
<gd:nameSuffix>II</gd:nameSuffix>
</gd:name>
<atom:content type="text">These are some testing notes.</atom:content>
<gd:email rel="http://schemas.google.com/g/2005#work" address="newtestAddress#gmail.com" primary="true" />
<gd:phoneNumber rel="http://schemas.google.com/g/2005#home" primary="true">716-999-0098</gd:phoneNumber>
<gd:phoneNumber rel="http://schemas.google.com/g/2005#work">666-8765-9087</gd:phoneNumber>
<gd:structuredPostalAddress rel="http://schemas.google.com/g/2005#home">
<gd:formattedAddress>3546 Madison Street, Chicago IL, 56879</gd:formattedAddress>
<gd:street>3546 Madison Street</gd:street>
<gd:city>Chicago</gd:city>
<gd:state>IL</gd:state>
<gd:country>USA</gd:country>
</gd:structuredPostalAddress>
</atom:entry>
But this doesn't
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005">
<atom:category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/contact/2008#contact" />
<gd:name>
<gd:givenName>Jack</gd:givenName>
<gd:familyName>Masters</gd:familyName>
<gd:fullName>Jack Masters</gd:fullName>
<gd:additionalName>Rascal</gd:additionalName>
<gd:namePrefix>Sir</gd:namePrefix>
<gd:nameSuffix>II</gd:nameSuffix>
</gd:name>
<atom:content type="text">These are some testing notes.</atom:content>
<gd:email rel="http://schemas.google.com/g/2005#work" address="newtestAddress#gmail.com" primary="true" />
<gd:email rel="http://schemas.google.com/g/2005#home" address="evenNewerAddress#yahoo.com" />
<gd:phoneNumber rel="http://schemas.google.com/g/2005#home" primary="true">716-999-0098</gd:phoneNumber>
<gd:phoneNumber rel="http://schemas.google.com/g/2005#work">666-8765-9087</gd:phoneNumber>
<gd:structuredPostalAddress rel="http://schemas.google.com/g/2005#home">
<gd:formattedAddress>3546 Madison Street, Chicago IL, 56879</gd:formattedAddress>
<gd:street>3546 Madison Street</gd:street>
<gd:city>Chicago</gd:city>
<gd:state>IL</gd:state>
<gd:country>USA</gd:country>
</gd:structuredPostalAddress>
<gContact:groupMembershipInfo href="http://www.google.com/m8/feeds/groups/default/base/14b3e56788eb41b8" />
</atom:entry>
I have tried a number of different gContact elements and nothing seems to work. I get a 400 HTTP response code every time.
This is the response detail. I can't seem to figure where the error is.
Optional(<NSHTTPURLResponse: 0x600000234480> { URL: https://www.google.com/m8/feeds/contacts/default/full?alt=json } { status code: 400, headers {
"Cache-Control" = "private, max-age=0";
"Content-Encoding" = gzip;
"Content-Type" = "text/plain; charset=UTF-8";
Date = "Tue, 07 Mar 2017 16:02:17 GMT";
Expires = "Tue, 07 Mar 2017 16:02:17 GMT";
Server = GSE;
"alt-svc" = "quic=\":443\"; ma=2592000; v=\"36,35,34\"";
"x-content-type-options" = nosniff;
"x-frame-options" = SAMEORIGIN;
"x-xss-protection" = "1; mode=block"; } })
You may want to try these recommended actions for error code 400 as given in Standard Error Responses:
invalidParameter
Do not retry without fixing the problem. You need to provide a valid value for the parameter specified in the error response.
badRequest
Do not retry without fixing the problem. You need to make changes to the API query in order for it to work.
You may want to also check this related SO post for additional insights that might help you.
I figured it out. I was literally formatting every gContact element that I was trying incorrectly. I had tried 4 separate things and wrongly assumed it was something contextual I hadn't set. In reality I had formatted all four wrong in different ways. New programmer lesson learned.

SSRS 2008 URL click-through with multi-value parameter not working but works if the string is manually entered

I'm attempting to create drill-through functionality to another report using Text Box Properties > Action > Go to URL , all parameters that are in the drill-through report are included in the url expression to ensure no defaults within the drill through report are used, and are specified in the order that they exist in the drill-through rdl.
#ReportIntermediary is a multi-value parameter, all others are single-value.
=Globals!ReportServerUrl
& "/reportserver?"
& replace(Globals!ReportFolder, " ", "+")
& "/Snapshot+Report"
& "&rs:Command=Render&rs:ParameterLanguage=en-AU&rc:Parameters=false"
& "&ReportRegion=National"
& "&ReportDate=" & Code.URLEncode(Format(Parameters!ReportDate.Value, "yyyy-MM-dd"))
& "&ReportIntermediaryGroup=" & CStr(Fields!GroupIntermediaryNo.Value)
& "&ReportNumberOfMonthsToShow=3"
& "&ReportIntermediaryState=National"
& Fields!ParameterIntermediaryList.Value
Where Fields!ParameterIntermediaryList.Value is formatted as:
&ReportIntermediary=123456789&ReportIntermediary=123456789
And a sample of the string that is formed by the expression being:
http://localhost/ReportServer/Pages/ReportViewer.aspx?/Folder/Sub+Folder/Snapshot+Report&rs:Command=Render&rs:ParameterLanguage=en-AU&ReportRegion=National&ReportDate=2013-06-01&ReportIntermediaryGroup=123456789&ReportNumberOfMonthsToShow=3&ReportIntermediaryState=National&ReportIntermediary=123456789&ReportIntermediary=123456789&ReportIntermediary=123456789
I have put the above expression in a text box within the row group of the matrix and the string appears to be well formed. When I take that string and manually enter it into IE address bar the report will render.
If the manual method will render, why won't the click-through behaviour be working in the report?
I have also tried setting the Go to URL expression to =ReportItems!txtLink.Value, where this text box holds the string value created by the expression above. This doesn't work either.
Here is the XML from within the rdl file:
<CellContents>
<Textbox Name="txtGroupIntermediaryName">
<KeepTogether>true</KeepTogether>
<Paragraphs>
<Paragraph>
<TextRuns>
<TextRun>
<Value>=Fields!GroupIntermediaryName.Value</Value>
<Style>
<FontSize>8pt</FontSize>
<TextDecoration>Underline</TextDecoration>
<Color>Blue</Color>
</Style>
</TextRun>
</TextRuns>
<ListLevel>1</ListLevel>
<Style />
</Paragraph>
</Paragraphs>
<ActionInfo>
<Actions>
<Action>
<Hyperlink>=Globals!ReportServerUrl
& "/reportserver?"
& replace(Globals!ReportFolder, " ", "+")
& "/Snapshot+Report"
& "&rs:Command=Render&rs:ParameterLanguage=en-AU&rc:Parameters=false"
& "&ReportSegment=Dealer"
& "&ReportRegion=National"
& "&ReportDate=" & Code.URLEncode(Format(Parameters!ReportDate.Value, "yyyy-MM-dd"))
& "&ReportIntermediaryGroup=" & CStr(Fields!GroupIntermediaryNo.Value)
& "&ReportNumberOfMonthsToShow=3"
& "&ReportIntermediaryState=National"
& Fields!ParameterIntermediaryList.Value</Hyperlink>
</Action>
</Actions>
</ActionInfo>
<Style>
<Border>
<Style>None</Style>
</Border>
<BackgroundColor>=iif(ReportItems!txtRowGroupBackgroundFormat.Value = 1, Code.ColourPalette("row-highlight"), Nothing)</BackgroundColor>
<PaddingLeft>2pt</PaddingLeft>
<PaddingRight>2pt</PaddingRight>
<PaddingTop>2pt</PaddingTop>
<PaddingBottom>2pt</PaddingBottom>
</Style>
</Textbox>
<rd:Selected>true</rd:Selected>
</CellContents>
The CStr function causes an error when trying to convert a multi-value parameter. Use the Join function instead. You can convert like this and use whatever separator you want:
Join(Fields!GroupIntermediaryNo.Value, ",")
The issue was caused by the text (within the textbox that has the Goto Url action on it) being indented for formatting purposes.
Removing this indentation allowed the action to work.
This can be done by any of the following methods:
Clicking the Decrease Indent button on the Report Formatting Toolbar
Selecting the textbox and then going to the Properties pane and setting ListLevel equal to 0
Going into the XML and finding the tag <ListLevel>1</ListLevel> and setting the 1 to 0 (this will be a larger number if the indentation is larger, e.g., 2, 3 ..., n)

Techniques for building HTML in code

An html template is compiled into the application as a resource. A fragment of the HTML template looks like:
<A href="%PANELLINK%" target="_blank">
<IMG border="0" src="%PANELIMAGE%" style="%IMAGESTYLE%">
</A><BR>
%CAPTIONTEXT%
i like it like this because the larger resource HTML file contains styling, no-quirks mode, etc.
But as is always the case, they now want the option that the Anchor tag should be omitted if there is no link. Also if there is no caption, then the BR tag should be omitted.
Considered Technique Nº1
Given that i don't want to have to build entire HTML fragments in C# code, i considered something like:
%ANCHORSTARTTAGPREFIX%<A href="%PANELLINK%" target="_blank">%ANCHORSTARTTAGPOSTFIX%
<IMG border="0" src="%PANELIMAGE%" style="%IMAGESTYLE%">
%ANCHORENDTAGPREFIX%</A>%ANCHORENDTAGPOSTFIX%CAPTIONPREFIX%<BR>
%CAPTIONTEXT%%CAPTIONPOSTFIX%
with the idea that i could use the pre and postfixes to turn the HTML code into:
<!--<A href="%PANELLINK%" target="_blank">-->
<IMG border="0" src="%PANELIMAGE%" style="%IMAGESTYLE%">
<!--</A>--><!--<BR>
%CAPTIONTEXT%-->
But that is just rediculous, plus one answerer reminds us that it wastes bandwith, and can be buggy.
Considered Technique Nº2
Wholesale replacement of tags:
%AnchorStartTag%
<IMG border="0" src="%PANELIMAGE%" style="%IMAGESTYLE%">
%AnchorEndTag%%CaptionStuff%
and doing a find-replace to change
%AnchorStartTag%
with
"<A href=\"foo\" target=\"blank\""
Considered Technique Nº3
i considered giving an ID to the important HTML elements:
<A id="anchor" href="%PANELLINK%" target="_blank">
<IMG border="0" src="%PANELIMAGE%" style="%IMAGESTYLE%">
</A><BR id="captionBreak">
%CAPTIONTEXT%
and then using an HTML DOM parser to programatically delete nodes. But there is no easy access to a trustworthy HTML DOM parser. If the HTML was instead xhtml i would use various built-in/nativly available xml DOM parsers.
Considered Technique Nº4
What i actually have so far is:
private const String htmlEmptyTemplate =
#"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01//EN\"""+Environment.NewLine+
#" ""http://www.w3.org/TR/html4/strict.dtd"">"+Environment.NewLine+
#"<HTML>"+Environment.NewLine+
#"<HEAD>"+Environment.NewLine+
#" <TITLE>New Document</TITLE>"+Environment.NewLine+
#" <META http-equiv=""X-UA-Compatible"" content=""IE=edge"">"""+Environment.NewLine+
#" <META http-equiv=""Content-Type"" content=""text/html; charset=UTF-8"">"+Environment.NewLine+
#"</HEAD>"+Environment.NewLine+
#""+Environment.NewLine+
#"<BODY style=""margin: 0 auto"">"+Environment.NewLine+
#" <DIV style=""text-align:center;"">"+Environment.NewLine+
#" %ContentArea%"+Environment.NewLine+
#" </DIV>" + Environment.NewLine +
#"</BODY>" + Environment.NewLine +
#"</HTML>";
private const String htmlAnchorStartTag =
#"<A href=""%PANELLINK%"" target=""_blank"">";
//Image is forbidden from having end tag
private const String htmlImageTag =
#"<IMG border=""0"" src=""%PANELIMAGE%"" style=""%IMAGESTYLE%"">";
private const String htmlCaptionArea =
#"<BR>%CAPTIONTEXT%";
And i already want to gouge my eyeballs out. Building HTML in code is a nightmare. It's a nightmare to write, a nightmare to debug, and a nightmare to maintain - and it will makes things difficult on the next guy. i'm hoping for another solution - since i am the next guy.
My reputation points in this game already being low gives me the freedom to tell you quite plainly that you, sir or madame, are in serious need of XSLT. Failing this (and you probably will) you need to look at XML literals in VB.NET (which provides you with the template-based solution you are looking for...). Since I prefer to stay in C# (even though I was born and raised on VBA), I use XSLT.
Both of my unwelcome recommendations require the use of XHTML instead of HTML. This requirement alone is quite a turn off to many traditional developers. I can already see through your use of capital letters for HTML elements that you will find my remarks utterly useless. So I should stop writing now.
What about this: Store XML as your fragment:
<fragment type="link_img_caption">
<link href="%PANELLINK%" />
<img src="%PANELIMAGE%" style="%IMAGESTYLE%" />
<caption text="%CAPTIONTEXT%" />
</fragment>
Pull it out, replace the placeholders with the "real" strings (that you have carefully XML-escaped of course),
...and use a simple XML transformation to produce HTML output:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="4.0" encoding="iso-8859-1" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="fragment" />
</xsl:template>
<xsl:template match="fragment[#type = 'link_img_caption']">
<xsl:choose>
<xsl:when test="link[#href != '']">
<a href="{link/#href}" target="_blank">
<img src="{img/#src}" style="{img/#style}" border="0" />
</a>
</xsl:when>
<xsl:otherwise>
<img src="{img/#src}" style="{img/#style}" border="0" />
</xsl:otherwise>
</xsl:choose>
<xsl:if test="caption[#text !='']">
<br />
<xsl:value-of select="caption/#text" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Other fragment types could be added because of the type attribute. There is much room to improve this, so look at it as an example of how it could be done.
Output:
<a href="%PANELLINK%" target="_blank">
<img src="%PANELIMAGE%" style="%IMAGESTYLE%" border="0">
</a>
<br>
%CAPTIONTEXT%
and, if the link href is empty in the XML:
<img src="%PANELIMAGE%" style="%IMAGESTYLE%" border="0">
<br>
%CAPTIONTEXT%
Use a templating engine, like one of these.
1.) Don't use comments, you'll send useless data to the browser wasting bandwidth and encountering BUGs in IE.
2.) Would this not be better as some sort of method? (I'm not familiar with C#) but something like this makes more sense to me.
//using PHP in this example
function HTMLImage($imageData, $linkData){
var str = '';
//if there is link data, start <a> tag
$str .= '<a '.{expand any attributes}.'>';
//add image tag and attributes from $imageData
$str .= '<img '.{expand any attributes}.'/>';
//if there is link data, close <a> tag
$str .= '</a>';
return $str;
}
I would use Template Toolkit, unfortunately it is currently only implemented in Perl and Python.
test.pl:
use Template;
my $template = Template->new({
VARIABLES => {
ImageStyle => "default",
CaptionText => "Place Caption Here"
},
});
$template->process( 'test.tt', {
panel => {
link => "http://Stackoverflow.com/",
image => "/Content/Img/stackoverflow-logo-250.png",
alt => "logo link to homepage"
}
} );
test.tt:
[% IF panel.link -%]
<A href="[% panel.link %]" alt="[% panel.alt %]" target="_blank">
[%- END -%]
[%- IF panel.image -%]
<IMG border="0" src="[% panel.image %]" style="[% ImageStyle %]">
[%- END -%]
[%- IF panel.link %]</A>[% END %]<BR>
[% CaptionText %]
Outputs:
<A href="http://Stackoverflow.com/" alt="logo link to homepage" target="_blank">
<IMG border="0" src="/Content/Img/stackoverflow-logo-250.png" style="default">
</A><BR>
Place Caption Here
If the variable panel.link isn't defined it skips the anchor tags.
<IMG border="0" src="/Content/Img/stackoverflow-logo-250.png" style="default">
<BR>
Place Caption Here
Templates are a serious code smell. Take a look at how Seaside generates html.
[Edit] Another one where someone without a clue downvoted.