0

I have a C# function like this in my XSLT stylesheet:

<xsl:stylesheet ...
    xmlns:utils="urn:local">

<msxsl:script language="CSharp" implements-prefix="utils">
    <![CDATA[
    public XmlDocument dateSplit(string str)
    {
      XmlDocument doc = new XmlDocument();
      XmlElement root = doc.CreateElement(string.Empty, "root", string.Empty);

      Regex rgx = new Regex("(?:(\\d{1,2})\\.(\\d{1,2})\\.)?(\\d{4})?");
      Match match = rgx.Match(str);

      XmlElement yearElem = doc.CreateElement(string.Empty, "year", string.Empty);
      XmlElement monthElem = doc.CreateElement(string.Empty, "month", string.Empty);
      XmlElement dayElem = doc.CreateElement(string.Empty, "day", string.Empty);

      if (match.Success) {

        string dayVal = match.Groups[1].Value;
        string monthVal = match.Groups[2].Value;
        string yearVal = match.Groups[3].Value;

        if (dayVal != "" && monthVal != "" && yearVal != "") {

          XmlText dayText = doc.CreateTextNode(dayVal.PadLeft(2, '0'));
          XmlText monthText = doc.CreateTextNode(monthVal.PadLeft(2, '0'));
          XmlText yearText = doc.CreateTextNode(yearVal);

          dayElem.AppendChild(dayText);
          monthElem.AppendChild(monthText);
          yearElem.AppendChild(yearText);

        } else if (yearVal != "") {

          XmlText yearText = doc.CreateTextNode(yearVal);
          yearElem.AppendChild(yearText);

        }
      }
      root.AppendChild(yearElem);
      root.AppendChild(monthElem);
      root.AppendChild(dayElem);

      doc.AppendChild(root);
      return doc;
    }
    ]]>
  </msxsl:script>

It turns "1960" into <year>1960</year>, "4.7.2016" into <year>2016</year><month>07</month><day>04</day> etc.

In order to add the elements year, month and day flat into my output XML...

<someOtherStuff>...</someOtherStuff>
<year>2016</year>
<month>07</month>
<day>04</day>
<moreStuff>...</moreStuff>

... I have to use the function like this:

<xsl:copy-of select="utils:dateSplit(myInput)/root/*"/>

I can't avoid the auxiliary <root> element in the dateSplit() function, because XmlDocument must be well-formed (only a single element at the top level). It's not possible to append multiple elements to the root.

Is there an alternative, something like a ResultTreeFragment, that does not ensure well-formedness in order to avoid the artificial and temporary <root> element?

CodeManX
  • 11,159
  • 5
  • 49
  • 70

1 Answers1

1

If you create an XmlDocumentFragment with CreateDocumentFragement then you can add your elements to that fragment and return it instead of the XmlDocument:

 <msxsl:script language="CSharp" implements-prefix="utils">
    <![CDATA[
    public XmlDocumentFragment dateSplit(string str)
    {
      XmlDocument doc = new XmlDocument();
      XmlDocumentFragment docFrag = doc.CreateDocumentFragment();

      // ...

      docFrag.AppendChild(yearElem);
      docFrag.AppendChild(monthElem);
      docFrag.AppendChild(dayElem);

      return docFrag;

And then use it like this:

<xsl:copy-of select="utils:dateSplit(myInput)"/>
CodeManX
  • 11,159
  • 5
  • 49
  • 70
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Thanks for the pointer in the right direction, it solved my problem! I submitted an edit to your answer to include my edited code using the fragment. – CodeManX Jun 08 '16 at 19:06