代码之家  ›  专栏  ›  技术社区  ›  Fabrizio RAHUL S R

如何使用XSLT转换XML?

  •  0
  • Fabrizio RAHUL S R  · 技术社区  · 6 年前

    我有一个XML文件和一个XSLT,我想使用XSLT将XML转换成一个HTML字符串,该字符串可以加载到 TWebBrowser .

    我的测试用的是 these 示例文件。

    <?xml version="1.0" encoding="UTF-8"?>
    <breakfast_menu>
    
    <food>
    <name>Belgian Waffles</name>
    <price>$5.95</price>
    <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
    <calories>650</calories>
    </food>
    
    <food>
    <name>Strawberry Belgian Waffles</name>
    <price>$7.95</price>
    <description>Light Belgian waffles covered with strawberries and whipped cream</description>
    <calories>900</calories>
    </food>
    
    <food>
    <name>Berry-Berry Belgian Waffles</name>
    <price>$8.95</price>
    <description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
    <calories>900</calories>
    </food>
    
    <food>
    <name>French Toast</name>
    <price>$4.50</price>
    <description>Thick slices made from our homemade sourdough bread</description>
    <calories>600</calories>
    </food>
    
    <food>
    <name>Homestyle Breakfast</name>
    <price>$6.95</price>
    <description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
    <calories>950</calories>
    </food>
    
    </breakfast_menu>
    

    XSLT文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
    <xsl:for-each select="breakfast_menu/food">
      <div style="background-color:teal;color:white;padding:4px">
        <span style="font-weight:bold"><xsl:value-of select="name"/> - </span>
        <xsl:value-of select="price"/>
        </div>
      <div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
        <p>
        <xsl:value-of select="description"/>
        <span style="font-style:italic"> (<xsl:value-of select="calories"/> calories per serving)</span>
        </p>
      </div>
    </xsl:for-each>
    </body>
    </html>
    

    尝试1:

    我找到了 this 解决方案并尝试函数:

    Uses
      XMLDoc, XMLIntf;
    
    function Transform(XMLContent : string; XSLContent : string) : WideString;
    var
      XML : IXMLDocument;
      XSL : IXMLDocument;
    begin
    
      XML := LoadXMLData(XMLContent);
      XSL := LoadXMLData(XSLContent);
    
      XML.DocumentElement.TransformNode(XSL.DocumentElement, Result)
    
    end;
    

    但它会产生一个意外的输出:

    著名的比利时华夫饼配大量真正的枫糖浆6500草莓 比利时华夫饼7.95美元覆盖草莓的轻比利时华夫饼 华夫饼上覆盖着各种新鲜浆果和鲜奶 面包600家庭早餐$6.95两个鸡蛋,培根或香肠,吐司和 我们一直流行的土豆泥


    尝试2:

    我在的“使用MSXML解析器/转换引擎”部分中找到了以下函数 this 页面(注意:这是一个Delphi5示例,但我使用的是Delphi2007)。

    function DoTransform(const xml, xsl : string ): string;
    var
      XMLDoc : IXMLDOMDocument;
      XSLDoc : IXMLDOMDocument;
      Template : IXSLTemplate;
      Processor : IXSLProcessor;
    begin
      Result := '';
      try
        XMLDoc := CoFreeThreadedDOMDocument30.Create;
        XSLDoc := CoFreeThreadedDOMDocument30.Create;
        XMLDoc.load(xml);
        XSLDoc.load(xsl);
        Template := CoXSLTemplate30.Create;
        Template.stylesheet := XSLDoc;
        Processor := Template.createProcessor;
        Processor.input := XMLDoc;
        Processor.transform;
        result :=  Processor.output;
      finally
        XMLDoc := nil;
        XSLDoc := nil;
      end;
    end;
    

    我已导入Microsoft XML类型库。。。

    组件->导入组件->导入类型库->下一步->Microsoft XML,v6.0

    …添加和 MSXML2_TLB uses子句,但也会出现一些其他错误:

    E2003未声明的标识符:“CoXSLTemplate30”

    我换了 CoFreeThreadedDOMDocument30 CoFreeThreadedDOMDocument60 CoXSLTemplate30 CoXSLTemplate60 现在它编译起来没有错误。

    在运行时,在这行:

    Template.stylesheet := XSLDoc;

    它引发了以下例外(意大利语):

    stile–vuoto oppure potrebessere un documento XML in format格式

    在英语中应该是这样的:

    为空,或者可能是格式错误的XML文档。

    我用其他示例文件进行了测试,错误总是一样的,我不知道哪一个可能是问题所在。

    我是在正确的道路上,还是有更好的方法来做我需要的?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Larsdk    6 年前

    我有下面的代码。它假设一个包含XSLT的文件,但这应该很容易更改。

    这是很久以前写的,我很匆忙。所以可能还有一些改进的空间。希望有帮助。

    uses
      Windows, ComObj, XMLDoc, msxmldom, msxml;
    
    function DOMToMSDom(const Doc: IDOMDocument): IXMLDOMDocument3;
    begin
      Result := ((Doc as IXMLDOMNodeRef).GetXMLDOMNode as IXMLDOMDocument3);
    end;
    
    function TransformXMLDocWithXSLTFile(const Doc: XMLIntf.IXMLDocument; const StyleSheetLocation: string; var TransformedData, Error: string): Boolean;
    var
      MsxmlDoc: IXMLDOMDocument3;
      xslStyle : IXMLDOMDocument;
    begin
      Result := False;
      if not FileExists(StyleSheetLocation) then 
      begin
        Error := 'Specified XSLT stylesheet file does not exist: ' + StyleSheetLocation;
        Exit;
      end;
      try
        MsxmlDoc := DOMToMSDom(Doc.DOMDocument);
        xslStyle := CoDOMDocument60.Create;
        xslStyle.load(StyleSheetLocation);
        IXMLDOMDocument3(xslStyle).setProperty('AllowXsltScript', True);
        TransformedData := MsxmlDoc.transformNode(xslStyle);
        Result := True;
      except
        on E: Exception do 
        begin
          Error := E.Message;
        end;
      end;
    end;
    
        2
  •  0
  •   Bryn Lewis    4 年前

    存在一些问题;

    XSL没有样式表、输出或根模板。它应该是这样的:

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
        <xsl:output method="html" encoding="UTF-8" />
    
        <xsl:template match="/">
            <html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
                <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
                    <xsl:for-each select="breakfast_menu/food">
                        <div style="background-color:teal;color:white;padding:4px">
                            <span style="font-weight:bold">
                                <xsl:value-of select="name"/> - </span>
                            <xsl:value-of select="price"/>
                        </div>
                        <div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
                            <p>
                                <xsl:value-of select="description"/>
                                <span style="font-style:italic"> (<xsl:value-of select="calories"/> calories per serving)</span>
                            </p>
                        </div>
                    </xsl:for-each>
                </body>
            </html>
        </xsl:template>
    </xsl:stylesheet>
    

    在delphi代码中,因为您正在加载字符串,所以应该使用.loadXML,而不是.load

        XMLDoc := CoFreeThreadedDOMDocument60.Create;
        XSLDoc := CoFreeThreadedDOMDocument60.Create;
        XMLDoc.loadXML(xml);
        XSLDoc.loadXML(xsl);
        
        Template := CoXSLTemplate60.Create;
        Template.stylesheet := XSLDoc;
        Processor := Template.createProcessor;
        Processor.input := XMLDoc;
        Processor.transform;
        s :=  Processor.output;
    

    在执行.load或.loadXML之后,您可以查看parseerror以检查发生了什么(如果您有问题的话)

    xsldoc.parseError.errorCode;  //will be 0 if all is well
    xsldoc.parseError.reason; 
    
        3
  •  0
  •   Fabrizio RAHUL S R    4 年前

    这是我的解决方案 德尔福2007 德尔福XE7 .

    uses
      msxml; 
    
    function Transform(const AXMLContent : string; const AXSLContent : string) : string;
    var
      XML : IXMLDOMDocument;
      XSL : IXMLDOMDocument;
    begin
      XML := CoDOMDocument.Create;
      XML.loadXML(AXMLContent);
    
      XSL := CoDOMDocument.Create;
      XSL.loadXML(AXSLContent);
    
      Result := XML.TransformNode(XSL);
    end;
    

    picture of the resulting styled xml

    生成的HTML代码:

    <html>
    <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
    <div style="background-color:teal;color:white;padding:4px"><span style="font-weight:bold">Belgian Waffles - </span>$5.95</div>
    <div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
    <p>Two of our famous Belgian Waffles with plenty of real maple syrup<span style="font-style:italic"> (650 calories per serving)</span></p>
    </div>
    <div style="background-color:teal;color:white;padding:4px"><span style="font-weight:bold">Strawberry Belgian Waffles - </span>$7.95</div>
    <div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
    <p>Light Belgian waffles covered with strawberries and whipped cream<span style="font-style:italic"> (900 calories per serving)</span></p>
    </div>
    <div style="background-color:teal;color:white;padding:4px"><span style="font-weight:bold">Berry-Berry Belgian Waffles - </span>$8.95</div>
    <div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
    <p>Light Belgian waffles covered with an assortment of fresh berries and whipped cream<span style="font-style:italic"> (900 calories per serving)</span></p>
    </div>
    <div style="background-color:teal;color:white;padding:4px"><span style="font-weight:bold">French Toast - </span>$4.50</div>
    <div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
    <p>Thick slices made from our homemade sourdough bread<span style="font-style:italic"> (600 calories per serving)</span></p>
    </div>
    <div style="background-color:teal;color:white;padding:4px"><span style="font-weight:bold">Homestyle Breakfast - </span>$6.95</div>
    <div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
    <p>Two eggs, bacon or sausage, toast, and our ever-popular hash browns<span style="font-style:italic"> (950 calories per serving)</span></p>
    </div>
    </body>
    </html>
    

    显示一个字符串 TWebBrowser 我使用了以下代码:

    procedure LoadHTMLCode(AWebBrowser : TWebBrowser; const AHTMLCode: string);
    var
      Doc: Variant;
    begin
      if not Assigned(AWebBrowser.Document) then
        AWebBrowser.Navigate('about:blank');
    
      Doc := AWebBrowser.Document;
      Doc.Clear;
      Doc.Write(AHTMLCode);
      Doc.Close;
    end;
    

    var
      XMLContent : string;
      XLSContent : string;
      HTMLCode : string;
    begin
      //loading XML content
      XMLContent := ...;
    
      //loading XLS content
      XLSContent := ...;
     
      //transforming
      HTMLCode := Transform(XMLContent, XLSContent);
    
      //displaying
      LoadHTMLCode(WebBrowser1, HTMLCode);  
    end;