使用 saxonHE (9.2.1.1) API 针对多个 XML 文件处理 XSLT (v2.0) 的应用
本文关键字:XSLT 处理 文件 v2 应用 XML saxonHE API 使用 | 更新日期: 2023-09-27 18:30:49
我有一个应用程序,它使用 SAXONHE 9.2.1.1 api 文件将 XML 数据转换为纯文本。 我的表单包含以下文本框
- XMLInput_FilePath
- XSLT_FilePath
- TextOutput_FilePath
在我的表单的 okButton_Click() 事件中,我有以下内容:
private void okButton_Click(object sender, EventArgs e) {
FileStream xsltTransform_FileStream = File.Open(xsltTransform_FilePath.Text, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
FileStream xmlInput_FileStream = File.Open(xmlInput_FilePath.Text, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
XmlTextReader modelFileXML = new XmlTextReader(xmlInput_FileStream);
modelFileXML.XmlResolver = null;
Processor processor = new Processor();
XdmNode input = processor.NewDocumentBuilder().Build(modelFileXML);
XsltTransformer xsltTransformer = processor.NewXsltCompiler().Compile(xsltTransform_FileStream).Load();
xsltTransformer.InputXmlResolver = null;
xsltTransformer.InitialContextNode = input;
Serializer serializer = new Serializer();
serializer.SetOutputFile(writeFile);
xsltTransformer.Run(serializer);
xsltTransform_FileStream.Close();
modelFileStream.Close();
}
在我的XMLInput文件的上下文中,有一个对另一个XML文件中数据的引用 - 见下文:
.XML:
<XMLInput_File
Name="XMLInput_File">
<Subsystem Name="Subsystem">
<Requirements Name="Requirement_1">
<Rows>
<Path Text="XMLInput2_File:/XMLInput2_File/Subsystem_1/Field_1" />
</Rows>
<Rows>
<Path Text="XMLInput2_File:/XMLInput2_File/Subsystem_1/Field_2" />
</Rows>
</Requirements>
<Requirements Name="Requirement_2">
<Rows>
<Path Text="XMLInput2_File:/XMLInput2_File/Subsystem_1/Field_3" />
</Rows>
<Rows>
<Path Text="XMLInput2_File:/XMLInput2_File/Subsystem_2/Field_1" />
</Rows>
</Requirements>
</Subsystem>
</XMLInput_File>
Text 属性是存储外部 XML 文件路径的位置,在上面的示例中,XML 文件名将为"XMLInput2_File.xml"。
XML2:
<XMLInput2_File Name="XMLInput2_File">
<Subsystem Name="Subsystem_1">
<Fields Name="Field_1">
S1_Field_One
</Fields>
<Fields Name="Field_2">
S1_Field_Two
</Fields>
<Fields Name="Field_3">
S1_Field_Three
</Fields>
</Subsystem>
<Subsystem Name="Subsystem_2">
<Fields Name="Field_1">
S2_Field_One
</Fields>
<Fields Name="Field_2">
S2_Field_Two
</Fields>
<Fields Name="Field_3">
S2_Field_Three
</Fields>
</Subsystem>
</XMLInput2_File>
XSLT:
<xsl:template match="/">
<xsl:for-each select ="//Rows/Path">
<xsl:variable name ="interfaceData" select ="@Text"/>
<xsl:variable name ="_intfModelName" select ="substring-before(@Text,':/')"/>
<xsl:variable name ="_intfFileName" select ="concat('../../OtherXMLFiles/',$_intfModelName,'.xml')"/>
<xsl:apply-templates select ="document($_intfFileName)/*[@Name=$_intfModelName]/*">
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
我正在使用Microsoft Visual Studion 2008专业版来测试我的转换,上述方案完全按照应有的方式工作 - document()更具体地引用外部文件。 但是,当我使用 C# Winform 应用程序和 saxon api 调用时,我的输出文件包含空白数据(空行)。
经过一些测试和互联网搜索,我得出的结论是 [在我的 XSLT] 中的相对路径没有按预期应用。 似乎 saxon api 调用从转换.exe文件的位置而不是输入文件(这是我更喜欢的)处理 document() 函数。
我一直在尝试对此问题进行更多 Internet 搜索,我对该问题是在我的 XSLT 文件中还是在 okButton_Click() 事件中的撒克逊 api 调用中感到困惑。 此外,我去过撒克逊人的网站和文档寻求帮助,但无济于事。
在 XSLT 中,使用
<xsl:apply-templates select ="document($_intfFileName, /)/*[@Name=$_intfModelName]/*">
如果您希望相对于输入文档(而不是样式表)解析相对 URL。
在撒克逊人帮助邮件列表中发布我的询问后,萨克森卡的迈克尔·凯(Michael Kay)帮助我解决了这个问题。 错误出在我的撒克逊 api 调用(C# 应用程序)中。 以下是更新的代码:
private void okButton_Click(object sender, EventArgs e) {
Processor processor = new Processor();
XdmNode input = processor.NewDocumentBuilder().Build(new Uri(inputFile));
XsltCompiler compiler = processor.NewXsltCompiler();
compiler.BaseUri = new Uri(inputFile);
XsltTransformer xsltTransformer = compiler.Compile(new Uri(transformFileTextBox.Text)).Load();
xsltTransformer.InitialContextNode = input;
Serializer serializer = new Serializer();
serializer.SetOutputFile(writeFile);
xsltTransformer.Run(serializer);
xsltTransform_FileStream.Close();
modelFileStream.Close();
}
"问题是您正在调用 document() 来解析相对 URI其基本 URI 未知。因为您使用子字符串之前进行计算相对 URI,参数是一个字符串,因此它将使用的基本 URI是样式表的样式。样式表的基本 URI 未知,因为您从流构建了样式表;在这种情况下,撒克逊默认到当前工作目录。您可以使用XsltCompiler.BaseUri 属性。- 迈克尔凯
所以,这就是我所做的
- 删除了两个文件流变量
- 创建了一个 XsltCompiler 对象并将 BaseUri 设置为输入文件
- 将 FileStream 签名替换为"new Uri(文件名)"签名
- 删除了这行代码'xsltTransformer.InputXmlResolver = null;'
我的输出是应该的。 非常感谢萨克森卡的迈克尔·凯(Michael Kay)帮助解决这个问题。-洛伦兹