Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

App using saxonHE (9.2.1.1) api to process XSLT (v2.0) against multiple XML files

I have an application that uses the SAXONHE 9.2.1.1 api files to transform XML data to plain text. My form has textboxes for

  1. XMLInput_FilePath
  2. XSLT_FilePath
  3. TextOutput_FilePath

On the okButton_Click() event of my form, I have the following:

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();
}

Within the context of my XMLInput file there is a reference to data in another XML file - see below:

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>

The Text attribute is where the external XML File path is stored, in the above example, the XML filename would be "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>

I'm using Microsoft Visual Studion 2008 Professional Edition to test my transform and the above scenario works exactly as it should - the document() referencing the external file more specifically. However, when I use my C# Winform app and the saxon api calls, my output file contains blank data (blank lines).

After a few tests and Internet searches, I came to the conclusion that the relative path [in my XSLT] is not being applied as it should. It seems that the saxon api calls process the document() function from the location of the transform.exe file and not the input file (which is what I'd prefer).

I've been trying to do more Internet searches on this issue and I'm confused of whether the issue is in my XSLT file or in the saxon api calls within the okButton_Click() event. Furthermore, I've been to saxon's website and documentation for help, but to no avail.

like image 604
Lorentz Avatar asked Apr 12 '12 15:04

Lorentz


1 Answers

In your XSLT, use

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

if you want the relative URL to be resolved relative to the input document (and not the stylesheet).

like image 132
Martin Honnen Avatar answered Sep 27 '22 23:09

Martin Honnen