【问题标题】:How to transform an XML using an XSLT?如何使用 XSLT 转换 XML?
【发布时间】:2019-05-30 08:17:04
【问题描述】:

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

对于我的测试,我使用these 示例文件。

XML 文件:

<?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;

但它会产生意想不到的输出:

比利时华夫饼$5.95我们的两个 著名的比利时华夫饼配大量真正的枫糖浆650草莓 比利时华夫饼$7.95轻薄的比利时华夫饼,上面覆盖着草莓 和鲜奶油900Berry-Berry 比利时华夫饼$8.95Light Belgian 华夫饼,上面覆盖着各种新鲜浆果并打发 cream900法式吐司$4.50用我们自制的酸面团制成的厚片 面包600家常早餐$6.95两个鸡蛋、培根或香肠、吐司和 我们广受欢迎的薯饼950


尝试 2:

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

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 未声明的标识符:'CoFreeThreadedDOMDocument30'

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

我已将CoFreeThreadedDOMDocument30 切换为CoFreeThreadedDOMDocument60 并将CoXSLTemplate30 切换为CoXSLTemplate60,现在它编译时没有错误。

在运行时,在这一行:

Template.stylesheet := XSLDoc;

它引发了以下异常(意大利语):

Il foglio disstile non include un elemento documento。雾霾 stile è vuoto oppure potrebbe essere un documento XML in formato non 正确的。

英文应该是这样的:

样式表不包含文档元素。样式表是 为空或可能是格式错误的 XML 文档。

我用其他示例文件测试过,错误总是一样,我不明白可能是哪个问题。

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

【问题讨论】:

    标签: xml delphi xslt delphi-2007


    【解决方案1】:

    我有以下有效的代码。它假设一个包含 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】:

      有几个问题;

      您的 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】:

        这是我在 Delphi 2007Delphi 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;
        

        生成的 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;
        

        【讨论】:

          猜你喜欢
          • 2021-12-22
          • 1970-01-01
          • 2015-07-11
          • 1970-01-01
          • 2011-08-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多