使用 XSLT 3.0 的 JSON 到 XML - 如何加载 JSON 源并调用 json-to-xml 函数?

Posted

技术标签:

【中文标题】使用 XSLT 3.0 的 JSON 到 XML - 如何加载 JSON 源并调用 json-to-xml 函数?【英文标题】:JSON to XML using XSLT 3.0 - how to load JSON source and call json-to-xml function? 【发布时间】:2019-09-09 20:15:19 【问题描述】:

我想用 XSLT 3.0 and its json-to-xml() function 试验(在 Delphi 代码中):

在 XSLT 3.0 中,入站文档可以是 JSON,而不是 XML。处理器可以获取该文档,使用 json-to-xml() 函数将其转换为特定的已知 XML 格式,通过模板对其进行处理,然后将结果输出转换回 JSON(或者可以将其转换为 html 5其他格式

但我被困在两个地方:

如何使用 JSON 字符串作为转换源?尝试将其加载到 TXMLDocument 给我(当然?)“格式错误”错误

然后我将如何应用“json-to-xml() 函数”。我发现的所有关于在 Delphi 中使用 XSLT 转换的示例都使用了 TransformNode 函数,如下面的代码。 lDoc.Node.json-to-xml 之类的东西不会编译。

.

var
  lDoc, lXSL, lRes: IXMLDocument;
  lUTF8Str        : UTF8String;
begin
  lDoc := LoadXMLData(AXMLString);
  lXSL := LoadXMLData(cRemoveNSTransform);
  lRes := NewXMLDocument;
  lDoc.Node.TransformNode(lXSL.Node,lRes);  // Param types IXMLNode, IXMLDocument
  lRes.SaveToXML(lUTF8Str);     

谁能指出我正确的方向?

【问题讨论】:

我怀疑是否有任何开发良好的 XSLT 3 API 或 Delphi 绑定。 XSLT 3 的主要主角是 Saxon 9.8 及更高版本(存在于 Java 版本、.NET 框架版本和 C/C++ 版本中)和 Altova Raptor。我猜 IXMLDocument 建议您在 Windows 上使用 Microsoft 的 MSXML,它是一个 XSLT 1 处理器。 Raptor 有一个 COM API,猜测 Windows 上的 Delphi 可以连接到它。不确定将 Delphi 连接到 Java 或 .NET 有多么容易,以便您可以使用开源的 Saxon HE。 【参考方案1】:

我将为我自己的问题编写一个“指南”,该问题不使用 XSLT,而是使用我们订阅的 IP*Works! Delphi components。

这至少可以给其他人一个可用的选项,或者一个粗略的想法如何“自己动手”。

我们使用 IP*Works! TipwJSON 和 TipwXML 组件。 诀窍是拦截JSON组件的解析,然后将检测到的数据写入XML组件。 这是来自测试应用程序的代码,展示了我们是如何做到的(我已经留下了登录代码):

TJSONTOXML = class(TIpwJSON)
            private
               FXML         : TipwXML;
               FLogLevel    : Integer;
               procedure ShowLogLine(AMsg: String);
               procedure InterceptJSONStartElement(Sender: TObject; const Element: string);
               procedure InterceptJSONEndElement(Sender: TObject; const Element: string);
               procedure InterceptCharacters(Sender: TObject; const Text: string);
               function GetXML: String;
            public
               property XML: String read GetXML;
               constructor Create(AOwner: TForm; ALogLevel: Integer); overload;  // For now testing on a Form
            end;

constructor TJSONTOXML.Create(AOwner: TForm; ALogLevel: Integer);
begin
   inherited Create(AOwner);
   FLogLevel := ALogLevel;
   Self.BuildDOM  := false;
   Self.OnStartElement := InterceptJSONStartElement;
   Self.OnEndElement   := InterceptJSONEndElement;
   Self.OnCharacters   := InterceptCharacters;
   FXML := TipwXML.Create(nil);
end;

procedure TJSONTOXML.InterceptJSONEndElement(Sender: TObject; const Element: string);
begin
   if Element = '' then  // End of array
   begin
      if FLogLevel > 2 then ShowLogLine('JSON parse EndElement - Array');
      FXML.EndElement;
   end
   else
   begin
      if FLogLevel > 2 then ShowLogLine('JSON parse EndElement - Element: ' + Element);
      FXML.EndElement;
   end;
end;

procedure TJSONTOXML.InterceptJSONStartElement(Sender: TObject; const Element: string);
begin
   if Element = '' then  // Start of array
   begin
      if FLogLevel > 2 then ShowLogLine('JSON parse StartElement - Array');
      FXML.StartElement('ARRAY','');
   end
   else
   begin
      if FLogLevel > 2 then ShowLogLine('JSON parse StartElement - Element: ' + Element);
      FXML.StartElement(Uppercase(Element),'');
   end;
end;

procedure TJSONTOXML.ShowLogLine(AMsg: String);
// Use WM_COPYDATA to send log info to form
var CopyDataStruct: TCopyDataStruct;
begin
  CopyDataStruct.dwData := 0;
  CopyDataStruct.cbData := 2 + 2 * Length(AMsg);
  CopyDataStruct.lpData := PChar(AMsg);
  SendMessage((Owner as TForm).Handle, WM_COPYDATA, (Owner as TForm).Handle, lParam(@CopyDataStruct));
end;

function TJSONTOXML.GetXML: String;
begin
   FXML.EndElement;
   Result := FXML.OutputData;
end;

procedure TJSONTOXML.InterceptCharacters(Sender: TObject; const Text: string);
var lText: String;
begin
   // Always surrounded by quotes, remove:
   lText := StripQuotes(Text);
   if FLogLevel > 2 then ShowLogLine('JSON parse characters: ' + lText);
   FXML.PutString(lText);
end;

这样你就可以

lJSONToXML := TJSONTOXML.Create(Self,FDataLogLvl);
// Get your JSON data from somewhere, e.g. a HTTP component. Then:
lJSONToXML.Inputdata := lData;
lJSONToXML.Parse;         // The Parse method initiates the parsing that was postponed by setting BuildDom := false
// The XML is now in the OutputData property of the TipwXML and can e.g. be retrieved by our:
lOutputData := lJSONToXML.XML;

注意:

XML 中没有命名空间信息 JSON 数组在转换为 XML 时会转换为名为 ARRAY 的节点 所有数据都保存在内存中

【讨论】:

以上是关于使用 XSLT 3.0 的 JSON 到 XML - 如何加载 JSON 源并调用 json-to-xml 函数?的主要内容,如果未能解决你的问题,请参考以下文章

XSLT 3.0 - 在 XSLT 3.0 xml-to-json() 中出现错误“重复键值”

xslt 3.0 json-to-xml 和 xml-to-json 转换

XSLT(2.0 或 3.0)方法将存储在 xml 中的每个逗号分隔值的整个 xml 复制到单独的 xml 文件中

Marklogic xml 转换中的 XSLT 3.0 支持

xml 使用XSLT的XML到JSON

如何判断我编写的 XSLT 3.0 是不是实际上是流式传输 XML?