Merge two xml files with xslt in ASP.NET

2019-08-08 18:13发布

I'm new to xslt, and I need to combine two xmls into one using xslt. As an initial exercise, I created three files, file1.xml, file2.xml, and transform.xslt, and figured out how to merge those by running file1.xml directly. This is how I did it:

In file1.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="transform.xslt"?>
<stuff>
    ...
</stuff>

In file2.xml:

<morestuff>
   ...
</morestuff>

In transform.xslt:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom-functions">
    <xsl:output method="xml" indent="yes" version="1.0" encoding="ISO-8859-1"/>
    <xsl:variable name="file2" select="document('file2.xml')" />
    <xsl:doing-stuff>
        ...
        <!-- contains references to $file2 -->
        ...
    </xsl:doing-stuff>
</xsl:stylesheet>

But I need to be able to do this through my C# ASP.NET code, and using given xml strings instead of xml files. Like so:

public string MergeXmls(string xml1, string xml2){
    string mergedXml;
    var xsltPath = HttpContext.Current.Server.MapPath("transform.xslt");
    //???
    return mergedXml;
}

How can I make this happen? I know I need to remove the references to document('file2.xml') from transform.xslt, but I don't know where to go from there.

2条回答
劫难
2楼-- · 2019-08-08 18:39

On the front end web page I use a System.Web.UI.WebControls.Xml object like this:

<asp:Xml ID="xmlDisplay" runat="server" />

In the code behind my function would be something like:

public void MergeXmls(string xml1, string xml2)
{
    string mergedXml = "<root>" + xml1 + xml2 + "</root>;
    xmlDisplay.DocumentContent = mergedXml;
    xmlDisplay.TransformSource = Server.MapPath("transform.xslt");
}

When you load your page, the xmlDisplay object will hold the result of loading data from the XML string found in mergedXml into the XSLT.

The code sample provided here does not address creating a valid XML string from the 2 strings passed as parameters, it simply concatenates the 2 which may work in some cases.

Your XSLT should then be adjusted so the XPaths to data elements match the paths to elements found in the mergedXml string. The XSLT will not have references to the source XML data files.

Hope that helps.

查看更多
我想做一个坏孩纸
3楼-- · 2019-08-08 18:40

This can be accomplished using the XmlPreloadedResolver class. This allows you to preload entities that will be used to resolve the document function in the XSLT.

The only caveat is that the URI's specified in the document function are treated as relative to the base URI of the XSLT document itself, so you have to use a slightly convoluted method to load it through an XmlReader so you can override the base URI.

public string MergeXml(string xml1, string xml2)
{
    XslCompiledTransform xslt = new XslCompiledTransform();
    XmlDocument xsltDoc = new XmlDocument();
    // Load the XSLT file through XmlReader to override the base URI.
    using( StreamReader reader = File.OpenText(HttpContext.Current.Server.MapPath("transform.xslt")) )
    using( XmlReader xmlReader = XmlReader.Create(reader, null, "file:///transform.xslt") )
    {
        xsltDoc.Load(xmlReader);
    }
    // Use XsltSettings to enable the use of the document() function.
    xslt.Load(xsltDoc, new XsltSettings(true, false), null);

    // Load the first XML file into a document
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml1);

    // Create the resolver and add the second file to it.
    XmlPreloadedResolver resolver = new XmlPreloadedResolver();
    resolver.Add(new Uri("file:///file2.xml"), xml2);

    using( StringWriter writer = new StringWriter() )
    using( XmlWriter xmlWriter = XmlWriter.Create(writer) )
    {
        // Pass the resolver to the transform
        xslt.Transform(doc, null, xmlWriter, resolver);
        return writer.ToString();
    }
}

The XmlPreloadedResolver class is only available in .Net 4.0 and higher, but if you're using an earlier version you can still derive a custom class from System.Xml.XmlResolver and implement similar functionality yourself.

查看更多
登录 后发表回答