0

I have a XSL script that has this towards the top:

<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
    <xsl:choose>
        <xsl:when test="$CSSFile1 !=''">
            <style type="text/css">
                <xsl:value-of select="$CSSFile1"/>
            </style>
        </xsl:when>
        <xsl:otherwise>
            <link rel="stylesheet" type="text/css" href="Workbook-S-140-PublicTalk-WatchtowerStudy-ServiceTalk-Videoconference2.css"/>
            <link rel="stylesheet" type="text/css" href="Workbook-S-140-PublicTalk-WatchtowerStudy-ServiceTalk-Zoom.css"/>
        </xsl:otherwise>
    </xsl:choose>
    <title>
        <xsl:value-of select="//Labels/Congregation"/>&#160;<xsl:value-of select="//Labels/Title" />
    </title>
</head>

As you can see, when $CSSFile1 is empty it should include two style sheets.

The above is part of a XSL / XML transformation that is used in a CHtmlView control in my MFC project and in itself it works fine.

But ...

I have a feature that allows the user to export the same data to a HTML file and it is support to do this using a C# DLL that I wrote which does it's own transformation using the same data. The code:

public bool TransformXMLToHTML(string strTransformXSLPath, string strScheduleXMLPath, string strScheduleHTMLPath)
{
    try
    {
        var xmlResolver = new XmlUrlResolver();
        XsltArgumentList argsList = new XsltArgumentList();

        string strRootPath = Path.GetDirectoryName(strTransformXSLPath);

        // Read the XSL file and locate all the CSS documents that are used
        int iFileCount = 0;
        string[] lines = File.ReadAllLines(strTransformXSLPath);
        foreach (string line in lines)
        {
            if ((line).Trim().Contains("text/css"))
            {
                int iHREFIndex = line.IndexOf("href=\"");
                if (iHREFIndex != -1)
                {
                    string strCSSFile = line.Substring(iHREFIndex + 6);

                    int iQuoteIndex = strCSSFile.IndexOf("\"");
                    if (iQuoteIndex != -1)
                    {
                        strCSSFile = strCSSFile.Substring(0, iQuoteIndex);

                        // Build full path and make sure the file exists
                        string strCSSFilePath = Path.Combine(strRootPath, strCSSFile);
                        if(File.Exists(strCSSFilePath))
                        {
                            // Establish the parameter name
                            iFileCount++;
                            string strParamName = "CSSFile" + iFileCount.ToString();

                            // Read the content and attach
                            string strCSSFileContent = File.ReadAllText(strCSSFilePath);
                            argsList.AddParam(strParamName, "", strCSSFileContent);
                        }
                    }
                }
            }
        }

        // Now perform the transformation
        XslCompiledTransform transformer = new XslCompiledTransform();
        transformer.Load(strTransformXSLPath, new XsltSettings { EnableDocumentFunction = true }, xmlResolver);

        using (StreamWriter sw = new StreamWriter(strScheduleHTMLPath))
        {
            transformer.Transform(strScheduleXMLPath, argsList, sw);
        }
    }
    catch (Exception ex)
    {
        SimpleLog.Log(ex);
        return false;
    }

    return true;
}

Something is going wrong because the transformation is supposed to embed both CSS files and it only ends up embedded the first one. There are no errors raised.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
  • 1
    Have you considered using XPath to identitfy the `link[@rel = 'stylesheet'][@type = 'text/css']` elements in the XSLT loaded as an XPathDocument or XmlDocument instead of parsing it as plain text? Perhaps that makes it easier reading out the `href` attribute values and then ckecking for the files. – Martin Honnen Jan 17 '21 at 17:10
  • @MartinHonnen I have not considered this approach. – Andrew Truckle Jan 17 '21 at 17:13

1 Answers1

2

First, I agree w/Martin re: XPath. Hand parsing XML / XSL is a red flag for me. Use all the tools available to you in XML / XSL and XPath. Have a look at XmlDocument.SelectNodes for looking up nodes and doing quick DOM manipulation. I know it's "out of the way", but a few minutes mastering XPath and DOM manipulation will pay dividends for a long time to come.

RE: Your issue

"the transformation is supposed to embed both CSS files and it only ends up embedded the first one."

When $CSSFile1 is present, the XSL only outputs $CSSFile1. However the second file content is output as a second parameter $CSSFile2 (that you're not outputting). You can resolve in two ways.

  1. Append content from CSSFile2 into your strCSSFileContent variable. Then "everything" will be contained in $CSSFile1
  • or alternatively -
  1. In your XSL output both CSSFile1 AND CSSFile2

Good luck, hope this is helpful to you.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
William Walseth
  • 2,803
  • 1
  • 23
  • 25
  • Thanks for your answer. I will certain look at using the alternative methodology. And based on your answer I was able to adjust my XSL logic as needed. Much appreciated. – Andrew Truckle Jan 17 '21 at 18:16