6

我有一个使用 SAXONHE 9.2.1.1 api 文件将 XML 数据转换为纯文本的应用程序。我的表单有文本框

  1. XMLInput_FilePath
  2. XSLT_FilePath
  3. 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 Professional Edition 来测试我的转换,并且上述场景完全可以正常工作 - document() 更具体地引用了外部文件。但是,当我使用 C# Winform 应用程序和 saxon api 调用时,我的输出文件包含空白数据(空白行)。

经过几次测试和 Internet 搜索后,我得出结论,相对路径 [在我的 XSLT 中] 没有按应有的方式应用。似乎 saxon api 调用从 transform.exe 文件的位置处理 document() 函数,而不是输入文件(这是我更喜欢的)。

我一直在尝试对这个问题进行更多的 Internet 搜索,但我对问题是在我的 XSLT 文件中还是在 okButton_Click() 事件中的 saxon api 调用中感到困惑。此外,我去过撒克逊的网站和文档寻求帮助,但无济于事。

4

2 回答 2

1

在您的 XSLT 中,使用

  <xsl:apply-templates select ="document($_intfFileName, /)/*[@Name=$_intfModelName]/*">

如果您希望相对于输入文档(而不是样式表)解析相对 URL。

于 2012-04-12T16:32:19.003 回答
0

在撒克逊帮助邮件列表上发布我的询问后,Saxonica 的 Michael Kay 帮助我解决了这个问题。错误出现在我的 saxon 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。因为您使用 substring-before 来计算相对 URI,所以参数是字符串,因此它将使用的基本 URI 是“ - 迈克尔·凯

所以,这就是我所做的

  • 删除了两个 FileStream 变量
  • 创建了一个 XsltCompiler 对象并将 BaseUri 设置为输入文件
  • 将 FileStream 签名替换为“new Uri(filename)”签名
  • 删除了这行代码'xsltTransformer.InputXmlResolver = null;'

我的输出是应该的。非常感谢 Saxonica 的 Michael Kay 帮助解决了这个问题。- 洛伦兹

于 2012-04-13T21:08:12.163 回答