XSLT invalid token results in invalid XML document - c#

I am using an XSLT file to transform an XML file to another XML file and then creating this XML file locally. I get this error:
System.InvalidOperationException: 'Token Text in state Start would result in an invalid XML document. Make sure that the ConformanceLevel setting is set to ConformanceLevel.Fragment or ConformanceLevel.Auto if you want to write an XML fragment. '
The XSLT file was debugged in visual studios and it looks like it works correctly but I don't understand this error. What does this mean and how can it be fixed?
This is my XML:
<?xml version="1.0" encoding="utf-8"?>
<In xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="take.xsd">
<Submit ID="1234">
<Values>
<Code>34</Code>
<Source>27</Source>
</Values>
<Information>
<Number>55</Number>
<Date>2018-05-20</Date>
<IsFile>1</IsFile>
<Location></Location>
<Files>
<File>
<Name>Red.pdf</Name>
<Type>COLOR</Type>
</File>
<File>
<Name>picture.pdf</Name>
<Type>IMAGE</Type>
</File>
</Files>
</Information>
</Submit>
</In>
My XSLT code:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<!-- identity template - copies all elements and its children and attributes -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="/In">
<!-- Remove the 'In' element -->
<xsl:apply-templates select="node()"/>
</xsl:template>
<xsl:template match="Submit">
<!-- Create the 'Q' element and its sub-elements -->
<Q xmlns:tns="Q" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://schema.xsd" Source="{Values/Source}" Notification="true">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates select="Values" />
<xsl:apply-templates select="Information" />
<xsl:apply-templates select="Information/Files" />
</xsl:copy>
</Q>
</xsl:template>
<xsl:template match="Information">
<!-- Create the 'Data' sub-element without all of its children -->
<xsl:copy>
<xsl:copy-of select="Number"/>
<xsl:copy-of select="Date"/>
<xsl:copy-of select="IsFile"/>
<xsl:copy-of select="Location"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
And this is the C# code used to transform the file:
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(#"D:\\Main\XLSTFiles\Test.xslt");
string xmlPath = #"D:\Documents\Test2.xml";
using (XmlWriter w = XmlWriter.Create(#"D:\Documents\NewFile.xml"))
{
xslt.Transform(xmlPath, w);
}
Also, is there a way to produce the new XML file with proper indentation? It seems to create each node after the last one is closed and on the custom template it just appends each item one after another.

It's an amazingly unhelpful message, isn't it? But I think I can decipher it for you.
The XSLT processor is producing its output by writing events such as start-document, start-element, output-text to an XML Writer.
If you want to produce a well-formed XML document, then you can't have any text before the start of the first element. The message is saying that if the last thing you did is to issue start-document, then the next thing isn't allowed to be text, because the document would be ill-formed (it says invalid, but it means ill-formed).
Now, XSLT stylesheets are allowed to produce "well-formed fragments" rather than only being allowed to write "well-formed documents". Actually, the term used in the XML spec is "well-formed external general parsed entity", but that's a bit of a mouthful, so everyone calls them "fragments" because that's what DOM calls them, and there's no point using correct terminology in error messages if no-one understands it. The difference is that a fragment can contain multiple elements and text nodes at the top level, for example this <b>really</b> is a <i>well-formed</i> fragment. The problem is that the destination to which you write the XSLT output might not handle fragments, and in this particular case, the XML Writer can handle a fragment only if it's configured to do so.
I suspect you didn't actually intend to produce a fragment, and you need to fix your XSLT code so it outputs a well-formed document.

To expand on Michael Kay's excellent answer (as this was too long to write in comments), for your particular input XML the issue is with whitespace. In the template matching /In you do this...
<xsl:template match="/In">
<!-- Remove the 'In' element -->
<xsl:apply-templates select="node()"/>
</xsl:template>
But by selecting node() you are selecting the whitespace nodes before and after the child Submit, so you end up with a text node before your root Q element causing the error.
So, what you could do in this case, is simply strip out the whitespace from your XML by adding this to your XSLT
<xsl:strip-space elements="*" />
Alternatively, you could also do this, to select only elements, as opposed other nodes (although this would omit comments and processing instructions)
<xsl:apply-templates select="*" />
However, if you have multiple Submit elements in your XML, you then get multiple Q elements in your output, which will be a fragment, as there would be a single root element. If this is what you really intend, then you should make the following change to your C#...
using (XmlWriter w = XmlWriter.Create(#"C:\Users\tcase.BGT\Documents\NewFile.xml", xslt.OutputSettings ))
The default ConformanceLevel is ConformanceLevel.Auto, which I think allows fragments. Adding this will also solve your indentation problem, as it will use the settings in your xsl:output.

Related

Error designing template XSLT to generate XML

I need to generate this XML:
<bdo_fosfec:RegistrosPagosElement xsi:type="bdo_fosfec:RegistrosPagos"
xmlns:bdo_fosfec="http://asocajas.app.com/example"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<registro54 xsi:type="bdo_fosfec:Registro54">
<registro82 xsi:type="bdo_fosfec:Registro82">
<C512>39756656</C512>
<C614>YAXMINNI</C614>
</registro82>
</registro54>
<registro54 xsi:type="bdo_fosfec:Registro54">
<registro82 xsi:type="bdo_fosfec:Registro82">
<C512>79374740</C512>
<C614>VICTOR</C614>
</registro82>
</registro54>
</bdo_fosfec:RegistrosPagosElement>
I built this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<bdo_fosfec:RegistrosPagosElement xsi:type="bdo_fosfec:RegistrosPagos" xmlns:bdo_fosfec="http://asocajas.app.com/example" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:apply-templates select="registro54"/>
</bdo_fosfec:RegistrosPagosElement>
</xsl:template>
<!--TEMPLATE REGISTRO 54-->
<xsl:template match="registro54">
<registro54 xsi:type="bdo_fosfec:Registro54">
<registro82 xsi:type="bdo_fosfec:Registro82">
<C512><xsl:value-of select="C512"/></C512>
<C614><xsl:value-of select="C614"/></C614>
</registro82>
</registro54>
</xsl:template>
</xsl:stylesheet>
But, when I load my XSLT on C#, I get an error.
var xslt = new XslCompiledTransform();
xslt.Load(myxslt);
XSLT compile error. 'xsi' is an undeclared prefix. Line 11, position 19.
It's as if the "xsi" of the second template could not reach the definition of the first template. How can I fix my XSLT?
I have made some modifications to XSLT but not generate the result I want, what is the correct xslt design?
Namespaces (and prefixes) in XSL can be tricky.
You need to declare any namespace you want to use in your XSL code. Since your XSL declares the namespace that goes with prefix xsi in a limited fashion, the XSL processor cannot process this prefix when it appears outside the scope of the declaration, and so it throws the error.
Try adding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" to the topmost xsl:stylesheet element in your XSL. Breaking this down:
The xmlns stands for "XML namespace".
The xsi is the prefix you want to use. This could be anything -- it doesn't have to match the prefix in the input XML.
The http://www.w3.org/2001/XMLSchema-instance part is the URI string identifying the namespace. This part must match the namespace URI in the input XML, or your templates will fail to match.
I note that you did add the namespace declaration on a different element: bdo_fosfec:RegistrosPagosElement. This is valid XSL, but this namespace only applies to the children of this element. The xsi prefix (that points to this namespace) is also used in a different template in your XSL code, and since the scope of the namespace declaration in bdo_fosfec:RegistrosPagosElement doesn't extend to this other template, your XSL processor correctly fails to compile your code.
What it would look like after fixing:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<bdo_fosfec:RegistrosPagosElement xsi:type="bdo_fosfec:RegistrosPagos"
xmlns:bdo_fosfec="http://asocajas.app.com/example">
<xsl:apply-templates select="registro54"/>
</bdo_fosfec:RegistrosPagosElement>
</xsl:template>
<!--TEMPLATE REGISTRO 54-->
<xsl:template match="registro54">
<registro54 xsi:type="bdo_fosfec:Registro54">
<registro82 xsi:type="bdo_fosfec:Registro82">
<C512><xsl:value-of select="C512"/></C512>
<C614><xsl:value-of select="C614"/></C614>
</registro82>
</registro54>
</xsl:template>
</xsl:stylesheet>

Get value from web.config into XSLT file

I have some values in my web.config that I want to access in my XSLT file. How do I do that?
I have done this to load the config file in my XSLT:
<xsl:variable name="config" select="document('..//Website//web.config')"/>
<p><xsl:value-of select="$config//appSettings/add[#key='Test']/#value"/>
</p>
After this I am stuck - nothing gets rendered.
Ok.I have done some changes.I have tried using a separate XML file and i am able to get value from the file in my variable.
<xsl:apply-templates select="document('TestXML.xml')/test/Tag1">
</xsl:apply-templates>
<xsl:template match="Tag1">
<xsl:choose>
<xsl:when test="#sName='myTest'">
<span>
<xsl:value-of select="#TestId" />
</span>
</xsl:when>
</xsl:choose>
</xsl:template>
I am still confused that while reading the web.config file(which is an xml file), i get an empty variable, but for a pure .xml file i get a value in my variable.
my Test.XML is this
<?xml version="1.0"?>
<test>
<Tag1 sName="myTest" TestId="328,329">
</Tag1>
</test>
Please help me as to how could i work with a Web.config file with values under <appsettings> section.
The document() function should receive a valid URI scheme. Double-slashes // are used in XPath but are not valid path separators in an URI. If your web.config file is in the Website directory which is a sibling of the directory where your XSLT is located, the syntax should be:
<xsl:variable name="config" select="document('../Website/web.config')"/>
Assuming the rest of your stylesheet is correct, the XPath expression in the value-of should work if the structure of the XML inside your web.config matches it.

Remove all CDATA nodes and replace with encoded text

So, I've got a massive XML file and I want to remove all CDATA sections and replace the CDATA node contents with safe, html encoded text nodes.
Just stripping out the CDATA with a regex will of course break the parsing. Is there a LINQ or XmlDocument or XmlTextWriter technique to swap out the CDATA with encoded text?
I'm not too concerned with the final encoding quite yet, just how to replace the sections with the encoding of my choice.
Original Example
---
<COLLECTION type="presentation" autoplay="false">
<TITLE><![CDATA[Rights & Responsibilities]]></TITLE>
<ITEM id="2802725d-dbac-e011-bcd6-005056af18ff" presenterGender="male">
<TITLE><![CDATA[Watch the demo]]></TITLE>
<LINK><![CDATA[_assets/2302725d-dbac-e011-bcd6-005056af18ff/presentation/presentation-00000000.mp4]]></LINK>
</ITEM>
</COLLECTION>
---
Sould Become
<COLLECTION type="presentation" autoplay="false">
<TITLE>Rights & Responsibilities</TITLE>
<ITEM id="2802725d-dbac-e011-bcd6-005056af18ff" presenterGender="male">
<TITLE>Watch the demo</TITLE>
<LINK>_assets/2302725d-dbac-e011-bcd6-005056af18ff/presentation/presentation-00000000.mp4</LINK>
</ITEM>
</COLLECTION>
I guess the ultimate goal is to move to JSON. I've tried this
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath( #"~/somefile.xml"));
string jsonText = JsonConvert.SerializeXmlNode(doc);
But I end up with ugly nodes, i.e. "#cdata-section" keys. It would take WAAAAY to many hours to have the front end re-developed to accept this.
"COLLECTION":[{"#type":"whitepaper","TITLE":{"#cdata-section":"SUPPORTING DOCUMENTS"}},{"#type":"presentation","#autoplay":"false","TITLE":{"#cdata-section":"Demo Presentation"},"ITEM":{"#id":"2802725d-dbac-e011-bcd6-005056af18ff","#presenterGender":"male","TITLE":{"#cdata-section":"Watch the demo"},"LINK":{"#cdata-section":"_assets/2302725d-dbac-e011-bcd6-005056af18ff/presentation/presentation-00000000.mp4"}
Process the XML with a XSLT that just copies input to output - C# code:
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(#"c:\temp\id.xslt");
transform.Transform(#"c:\temp\cdata.xml", #"c:\temp\clean.xml");
id.xslt:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Using LINQ to XML, you can do it like this:
XDocument doc = …;
var cDataNodes = doc.DescendantNodes().OfType<XCData>().ToArray();
foreach (var cDataNode in cDataNodes)
cDataNode.ReplaceWith(new XText(cDataNode));
I think you can load the xml into a XmlDocument class. Then recursively process each XmlNode and look for XmlCDataSection node. This XmlCDataSection node should be replaced withXmlTextNode with same value.

Trying to generate objects for an XML file I have

I have an XML file, I need to extract values from it, and put them in another XML file.
Questions:
Another person is creating the "schema" for the resulting XML file. Is there something that person can give me that will automate the inserting of the values? Do I even need to extract anything from the XML, or can something like a XSLT just do all the transformation?
Is there a problem with this XML structure below? I tried using xsd2code to generate objects but nothing will load when I use the LoadFromFileMethod - I read an article that wasn't very specific but said "nested parents" cause problems for XSD.exe and xsd2code.
<Section>
<Form id="1"...>
<Control id="12523"..> <--Some have this some don't
<Property name="Color">Red</Property>
<Property name="Size">Large</Property>
</Control>
</Form>
<Form id="2"...>
<Property name="Color">Blue</Property>
<Property name="Size">Large</Property>
</Form>
<Form id="3"...>
<Property name="Color">Red</Property>
<Property name="Size">Small</Property>
</Form>
</Section>
Thank you for any guidance!
XSLT is the tool for XML transformation.
As far as your XML goes, in a lot of applications you should replace this:
<Property name="Color">Red</Property>
with:
<Color>Red</Color>
Some reasons:
If you want to write a schema that restricts an element's content in some way (e.g. to one of a list of values), the element must be identifiable by its name; you can't write one schema for a Property element with a name attribute equals "Color" and another schema for a Property element whose name attribute equals "Size".
It's easier to write XPath predicates if your element names are meaningful. For instance, Form[Color = 'Red'] is a lot easier to write (and read) than Form[Property[#name='Color' and .='Red']]
The above is also true if you're writing Linq queries against the XML, in pretty much the same manner. Compare Element.Descendants("Color") with Element.Descendents("Property").Where(x => x.Attributes["name"] == "Color").
There are applications where it's appropriate to have generically-named elements, too; the above argument's not definitive. But if you're going to do that, you should have good reasons.
XLST is the best way to transform xml from one schema to another. Thats exactly what it was built to do. http://w3schools.com/xsl/default.asp is an excellent XSLT tutorial. All you really need is the schema, or a few examples of his xml to write your xslt file.
Also, your xml looks fine/well-formed to me.
XSLT is probably the solution if you just want to transform it, but if you need to do anything with the values in code then LINQ to Xml will make your task much easier.
I'd use XSLT for this, here's a small example to get you started.
Copy this sample code to an empty c# project:
static void Main(string[] args) {
const string xmlPath = "source.xml";
const string xslPath = "transform.xsl";
const string outPath = "out.xml";
try {
//load the Xml doc
var xmlDoc = new XPathDocument(xmlPath);
//load the Xsl
var xslDoc = new XslCompiledTransform();
xslDoc.Load(xslPath);
// create the output file
using (var outDoc = new XmlTextWriter(outPath, null)) {
//do the actual transform of Xml
xslDoc.Transform(xmlDoc, null, outDoc);
}
}
catch (Exception e) {
Console.WriteLine("Exception: {0}", e.ToString());
}
}
Write your example xml code above into source.xml file and put the following xsl code into transform.xsl file:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="xml" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="Section">
<OtherSection>
<xsl:apply-templates />
</OtherSection>
</xsl:template>
<xsl:template match="Form">
<OtherForm>
<xsl:attribute name="id">
<xsl:value-of select="#id" />
</xsl:attribute>
<xsl:apply-templates />
</OtherForm>
</xsl:template>
<xsl:template match="Control">
<OtherControl>
<!-- converts id attribute to an id tag -->
<id>
<xsl:value-of select="#id" />
</id>
<xsl:apply-templates />
</OtherControl>
</xsl:template>
<xsl:template match="Property">
<OtherProperty>
<!-- converts name attribute to an id attribute -->
<xsl:attribute name="id">
<xsl:value-of select="#name" />
</xsl:attribute>
<xsl:value-of select="."/>
</OtherProperty>
</xsl:template>
</xsl:stylesheet>
The resulting out.xml should give you an idea of how the xsl is doing the work and hopefully get you started.
For more info on XSLT look up the tutorial on W3Schools.

XML iteration and rearrangement- C#

I Have an XML file like the one below:
<?xml version="1.0" ?>
<System>
<LP1>
<Equipment>
<FromName>Receptacle</FromName>
<Wire>1-#10, 1-#10, 1-#10</Wire>
<Length>89.8411846136344</Length>
</Equipment>
</LP1>
<X-1>
<Equipment>
<FromName>LP1</FromName>
<Wire>3-#3/0, 1-#3/0, 1-#6</Wire>
<Length>10.170412377555</Length>
</Equipment>
</X-1>
<HP1>
<Equipment>
<FromName>X-1</FromName>
<Wire>3-#3/0, 1-#3/0, 1-#6</Wire>
<Length>8.2423259796908</Length>
</Equipment>
<Equipment>
<FromName>AH-1</FromName>
<Wire>3-#6, 1-#10</Wire>
<Length>32.4019419736209</Length>
</Equipment>
<Equipment>
<FromName>EF-1</FromName>
<Wire>3-#12, 1-#12, 1-#12</Wire>
<Length>8.33572105849677</Length>
</Equipment>
</HP1>
</System>
I need to read it, and re-arrange it to look:
<?xml version="1.0" ?>
<HP1>
<Equipment>
<FromName>X-1</FromName>
<Wire>3-#3/0, 1-#3/0, 1-#6</Wire>
<Length>8.2423259796908</Length>
<Equipment>
<FromName>LP1</FromName>
<Wire>3-#3/0, 1-#3/0, 1-#6</Wire>
<Length>10.170412377555</Length>
<Equipment>
<FromName>Receptacle</FromName>
<Wire>1-#10, 1-#10, 1-#10</Wire>
<Length>89.8411846136344</Length>
</Equipment>
</Equipment>
</Equipment>
<Equipment>
<FromName>AH-1</FromName>
<Wire>3-#6, 1-#10</Wire>
<Length>32.4019419736209</Length>
</Equipment>
<Equipment>
<FromName>EF-1</FromName>
<Wire>3-#12, 1-#12, 1-#12</Wire>
<Length>8.33572105849677</Length>
</Equipment>
</HP1>
</System>
Basically, the original XML has separate Elements (LP1, X-1, HP1) that I want to put as sub elements when the equipment "FromName" matches the parent element name of the system.
I am guessing that I will need to do some recursive function, but I am kind of new to C# and programming in general and haven't had much experience with XML or recursive function.
Any help would be appreciated.
Thank you
While it can be definitely compressed to a one-liner as Steven suggested :) I chose to sprawl around a bit to make it more understandable. Of course I still failed so I'll also explain a bit.
XDocument x = XDocument.Parse(xml);
Func<string, XName> xn = s => XName.Get(s, "");
var systems = x.Elements().First();
var equipments = x.Descendants(xn("Equipment"));
equipments.ToList().ForEach(e =>
{
string fromName = e.Element(xn("FromName")).Value;
var found = systems.Element(xn(fromName));
if (found != null)
{
e.Add(found.Elements(xn("Equipment")));
found.Remove();
};
});
string result = x.ToString();
Assuming xml is the string in the OP, I simply parsed an XDocument from it. Then, a simple shortcut for getting XNames, since the code would have been even more crowded with it inline.
We get all the child elements of System and store it for later; for lack of a better term I called them systems. If there are multiple levels on which these elements may appear, the logic will of course need to be adjusted to find them all reliably.
Then we iterate through all the elements with the name Equipment (equipments), get the FromName element value, and search for an element with the same name in systems. If we find it, we simply add it to the current element and remove it from its parent; since the elements are still all part of the x tree, it works as expected.
Aaand... done. result is the desired result posted by the OP.
There are more than a few tutorials on XML file manipulation. Example of both save & load (reversed for tutorial, but both there):
http://www.java2s.com/Code/CSharp/XML/Loadxmldocumentfromxmlfile.htm
The steps should be roughly...
open Input file
Load input into XmlNodeList
Parse input into ouput XmlNodeList()
Save output into new file.
I actually think I see what your wanting, after a bit of staring... I'd have to tink about the parse step for a bit personally.
If Xml output is what you're after, Xslt is probably your best bet. You'll need to load the xml and stylesheet into memory and then process accordingly. Something like:
// load the stylesheet
XslTransform stylesheet = new XslTransform();
stylesheet.Load(xsltFilePath);
// load the xml
XPathDocument doc = new XPathDocument(xmlFilePath);
//create the output stream
XmlTextWriter myWriter = new XmlTextWriter("output.xml", null);
// autobots! Transform!
stylesheet.Transform(doc, null, myWriter);
myWriter.Close();
Regarding the stylesheet, I'm assuming that you'd be taking the last node in the xml file and then nesting the Equipment nodes from above. In order to do the recursive lookups, you'll need a special xslt feature that ships as part of the MSXML parser, specifically ms:node-set. This function let's you perform an xpath query and return a node rather than raw text.
Tip: Xslt is processed from the bottom up, so scroll down and then read-up.
PS -- I'm doing this from memory. Xslt can be finicky so you may want to play with this a bit.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt"
>
<!-- wildcard: other content is copied as is -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<!-- this is our magic recursive template. Any element that matches "Equipment"
will caught and processed here. Everything else will default to our
Wildcard above -->
<xsl:template match="Equipment">
<!-- Read the FromName element into the variable $fromName -->
<xsl:variable name="fromName" select="FromName/text()" />
<!-- Manually reconstruct the Equipment Node -->
<Equipment>
<!-- copy out FromName, Wire and Length -->
<xsl:copy-of select="FromName" />
<xsl:copy-of select="Wire" />
<xsl:copy-of select="Length" />
<!-- this is how we recursively pull our Element nodes in, which
will match on this template -->
<xsl:apply-templates select="ms:node-set('//' + $fromName')/Equipment" />
</Equipment>
</xsl:template>
<!-- Starting point: Find the last node under system -->
<xsl:template match="/System/*[last()]">
<!-- copy the elements and attributes of this node to the output stream -->
<xsl:copy>
<!-- match templates on its contents -->
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Categories