GerixSoft Blog

Drupal in WordPress LinkedIn application

In this article I will show how I have integrated Drupal feed from www.gerixsoft.com into WordPress application on LinkedIn.

When I first tried to add GerixSoft's feed into WordPress application, it refused saying "Only WordPress feeds are supported". After comparing Drupal and WordPress feeds, I have figured out they are using the same RSS standard. The only difference is meta "generator" element, absent on Drupal but present on WordPress XML.

Wild guess have confirmed that WordPress is using this string to block RSS from non-WordPress platforms.

To fix this, open includes/common.inc, locate format_rss_channel function and apply the following patch:

 /**
 * Formats an RSS channel.
 *
 * Arbitrary elements may be added using the $args associative array.
 */
function format_rss_channel($title, $link, $description, $items, $langcode = NULL, $args = array()) {
  global $language;
  $langcode = $langcode ? $langcode : $language->language;

  $output = "<channel>\n";
  $output .= ' <title>'. check_plain($title) ."</title>\n";
  $output .= ' <link>'. check_url($link) ."</link>\n";

  // The RSS 2.0 "spec" doesn't indicate HTML can be used in the description.
  // We strip all HTML tags, but need to prevent double encoding from properly
  // escaped source data (such as &amp becoming &amp;amp;).
  $output .= ' <description>'. check_plain(decode_entities(strip_tags($description))) ."</description>\n";
  
  
  // © by Andriy Gerasika from GerixSoft, Ltd.
  $output .= "<generator>http://wordpress.org/?v=MU</generator>\n";


  $output .= ' <language>'. check_plain($langcode) ."</language>\n";
  $output .= format_xml_elements($args);
  $output .= $items;
  $output .= "</channel>\n";

  return $output;
}

Note, when you'll be resubmitting feed into WordPress application, it still might say feed is not from WordPress – just try several times and it will accept the feed ultimately (seems there is some sort of cache on the server).

XSLT fn:name() is evil

XSLT name() function is evil and should be avoided just like GoTo.

For example, it is very bad to write

<xsl:apply-templates select="*[name()!='a:b']"/>

because it will exclude both of

<a:b/>
<a:b xmlns:a="totallyDifferentNamespace"/>

the correct way to write above apply-templates is

<xsl:apply-templates select="*[not(self::a:b)]"/>

or in XSLT 2.0

<xsl:apply-templates select="* exclude a:b"/>

assuming xmlns:a="someSpecificNamespace"

Test code is attached below.

xsl:include/@mode

The XML Pipeline in XSLT technique requires every xsl:template and xsl:apply-templates in the chained stylesheet to have mode attribute.

This could be simplified if XSLT would allow specifying mode in xsl:include. So <xsl:include href="link1.xsl" mode="link1"/> would mean "use link1 as default mode in link1.xsl":

  1. if xsl:template or xsl:apply-templates in the contained stylesheet do not have mode attribute, they receive it from xsl:include the stylesheet was included with
  2. if you still want to reference default mode from link1.xsl, you should use mode="#default"
  3. if link1.xsl includes identity.xsl, link1 mode is tunneled to identity.xsl.

If xsl:include/@mode would be available in XSLT processors, XML Pipeline code would look much simpler:

  • chain.xsl
    <?xml version="1.0" encoding="utf-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common">
    
        <xsl:output method="xml" omit-xml-declaration="no" indent="no" encoding="UTF-8"/>
    
        <xsl:include href="link1.xsl" mode="link1"/>
        <xsl:include href="link2.xsl" mode="link2"/>
        <xsl:include href="link3.xsl" mode="link3"/>
    
        <xsl:template match="/">
            <xsl:variable name="link1">
                <xsl:apply-templates mode="link1" select="node()"/>
            </xsl:variable>
            <xsl:variable name="link2">
                <xsl:apply-templates mode="link2" select="exsl:node-set($link1)/node()"/>
            </xsl:variable>
            <xsl:variable name="link3">
                <xsl:apply-templates mode="link3" select="exsl:node-set($link2)/node()"/>
            </xsl:variable>
    
            <xsl:copy-of select="exsl:node-set($link3)/node()"/>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • link1.xsl
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    	<xsl:import href="identity.xsl" />
    
        <xsl:template match="a">
            <aa>
                <xsl:apply-templates select="@*|node()"/>
                <b/>
            </aa>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • link2.xsl
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    	<xsl:import href="identity.xsl" />
    
        <xsl:template match="b">
            <bb>
                <xsl:apply-templates select="@*|node()"/>
                <c/>
            </bb>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • link3.xsl
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    	<xsl:import href="identity.xsl" />
    
        <xsl:template match="c">
            <cc>
                <xsl:apply-templates select="@*|node()"/>
            </cc>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • identity.xsl
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
        <xsl:template priority="-9" match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
    </xsl:stylesheet>
    

Attached you can find my patches to Saxon 9.1 and Xalan-J 2.7.1 enabling @mode in xsl:include.

XML Pipeline in XSLT

Most often people implement XML Pipeline in regular programming languages, sequentially invoking XSLT transformations one-by-one, "manually" feeding resulting output from one transformation to another.

Bespoke slow performance, this results in lesser flexibility since people stop using XSLT's declarative power and revert back to imperative world, which is not acceptable for XML transformations.

In this article I will show the most efficient way of implementing XML Pipeline using native XSLT capabilities.

The code outlining the approach consists of the following files:

  • chain.xsl, the "magic", main file implementing the pipeline. [1]
    <?xml version="1.0" encoding="utf-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common">
    
        <xsl:output method="xml" omit-xml-declaration="no" indent="no" encoding="UTF-8"/>
    
        <xsl:include href="link1.xsl"/>
        <xsl:include href="link2.xsl"/>
        <xsl:include href="link3.xsl"/>
    
        <xsl:template match="/">
            <xsl:variable name="link1">
                <xsl:apply-templates mode="link1" select="node()"/>
            </xsl:variable>
            <xsl:variable name="link2">
                <xsl:apply-templates mode="link2" select="exsl:node-set($link1)/node()"/>
            </xsl:variable>
            <xsl:variable name="link3">
                <xsl:apply-templates mode="link3" select="exsl:node-set($link2)/node()"/>
            </xsl:variable>
    
            <xsl:copy-of select="exsl:node-set($link3)/node()"/>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • link1.xsl, linked transformation:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
        <xsl:template priority="-9" mode="link1" match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates mode="link1" select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template mode="link1" match="a">
            <aa>
                <xsl:apply-templates mode="link1" select="@*|node()"/>
                <b/>
            </aa>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • link2.xsl, linked transformation:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
        <xsl:template priority="-9" mode="link2" match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates mode="link2" select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template mode="link2" match="b">
            <bb>
                <xsl:apply-templates mode="link2" select="@*|node()"/>
                <c/>
            </bb>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • link3.xsl, linked transformation:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
        <xsl:template priority="-9" mode="link3" match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates mode="link3" select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template mode="link3" match="c">
            <cc>
                <xsl:apply-templates mode="link3" select="@*|node()"/>
            </cc>
        </xsl:template>
    
    </xsl:stylesheet>
    

The key point of this approach is usage of EXSLT node-set function. This function converts result-nodes back into source-nodes. This way output of link1.xsl is fed as input to link2.xsl, and output of link2.xsl is fed as input to link3.xsl. [2]

This approach leverages full power of XSLT, it is fast and declarative. Transformations are applied without leaving XSLT processor, non-linear pipelines can be implemented easily:

        <xsl:variable name="link2">
            <!-- some logic whether or not launch link2.xsl -->
            <xsl:choose>
                <xsl:when test="not(.//d)">
                    <xsl:apply-templates mode="link2" select="exsl:node-set($link1)/node()"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="exsl:node-set($link1)/node()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>

I am using this technique for a number of years, and so far it works great.

[1] By default MSXML does not implement EXSLT, though it does have node-set function. It is in the xmlns:msxsl="urn:schemas-microsoft-com:xslt" namespace. There is chain_msxml.xsl — separate main file for MSXML that is using node-set function from msxsl namespace.
[2] xsl:copy-of in the last statement is included for debugging purposes. For example, if something goes wrong in link2.xsl, just change one symbol in xsl:copy-of to make it look like <xsl:copy-of select="exsl:node-set($link23)/node()"/> and pipeline will stop at 2nd transformation.
[3] exslt:node-set() is not required for XSLT 2.0 processor

Sample code is attached below.

Uninstall Feedback in InnoSetup

If user is uninstalling your application, it is reasonable to ask him what he did not liked in the application. Usually developers open web browser for submission of feedback.

I think this is not a good practise — most users do not like applications opening web browser without their confirmation. My opinion it is a lot better to implement sending of such kind of feedback using desktop's regular mail application, such as Outlook and Thunderbird.

For example, this is IndieVolume Uninstall Feedback window:

This is InnoSetup pascal code I have developed to implement above window:

#include "fixfonts.iss"
#include "feedback.iss"

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  if CurUninstallStep = usUninstall then
  begin
    UninstallFeedback('IndieVolume Uninstall Feedback', 'Send', 'Cancel',
      'To help us with future versions of IndieVolume, we want to know about any troubles or difficulties you have experienced while using IndieVolume.'#13#10  +
      ''#13#10'Please let us know why are you uninstalling IndieVolume. Thank You.',
      'support@gerixsoft.com', 'IndieVolume Uninstall Feedback');
  end;
end;                

 Attached you can find feedback.iss. For fixfonts.iss see this post

System Font in InnoSetup

InnoSetup does not support Windows system font, it is using MS Sans Serif 8 instead.

Use the following code to fix this:

#include "fixfonts.iss"

procedure InitializeWizard();
begin
  SetSystemFont(WizardForm.Font);
  FixSystemFont(WizardForm);
end;

fixfonts.iss is attached below. This code has been in use in IndieVolume for years, confirmed to work ok.

System Font in InputQuery Delphi Function

If you have applied my techniques fixing Large Fonts and System Font to all forms in your Delphi application, most likely there will be two forms still untouched. These will be the forms hidden inside MessageDlg and InputQuery VCL functions.

Fortunately, MessageDlg supports Large Fonts and System Font ok, but InputQuery supports only Large Fonts. In this post I will show how to modify InputQuery to support System Font.

Screenshot: Original InputQuery when System Font is Tahoma, DPI=120

InputQuery not supporting System Font

InputQuery implementation is hidden inside VCL, so a patch to VCL source code is needed.

  1. Locale Dialogs.pas unit in VCL source folder
  2. Save As Dialogs.pas to project folder using NewDialogs.pas file name
  3. Go to Project/Options/Directories/Conditionals/Aliases/Unit Aliases and define new unit alias: Dialogs=NewDialogs
  4. Locate InputQuery function in implementation part of NewDialogs.pas unit
  5. Insert code from previous post System Font right before "if ShowModal = mrOk then" line
  6. Build the project

The resulting InputQuery window will look like:

New InputQuery supporting System Font

Syndicate content