Comma separated string parsing XSLT to for-each node

后端 未结 3 1435
無奈伤痛
無奈伤痛 2021-02-07 12:59

I have an input string which has csv values. Eg., 1,2,3 I would need to separate each values and assign to target node in for-each loop.

I got this below template that s

3条回答
  •  Happy的楠姐
    2021-02-07 13:38

    Personally, I prefer this variant based on custom extension functions. The method is compact and clean, and works fine in XSLT 1.0 (at least with XALAN 2.7 as embedded in any recent JVM).

    1) declare a class with a static method returning a org.w3c.dom.Node

    package com.reverseXSL.util;
    
    import org.w3c.dom.*;
    import java.util.regex.*;
    import javax.xml.parsers.DocumentBuilderFactory;
    
    public class XslTools {
    
      public static Node splitToNodes(String input, String regex) throws Exception {
        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        Element item, list = doc.createElement("List");
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(input);
        while (m.find()) {
          item = doc.createElement("Item");
          StringBuffer sb = new StringBuffer();
          for (int i=1; i<=m.groupCount(); ++i) if (m.start(i)>=0) sb.append(m.group(i));
          Text txt = doc.createTextNode(sb.toString());
          item.appendChild(txt);
          list.appendChild(item);
        }
        return list; 
      }
    
    }
    

    This function splits an input string on a regex pattern and creates a document fragment of the kind ABC. The regex is matched in sequence, each match yielding an Item element whose value is composed from the capturing groups (some possibly empty) inside each regex match. This allows to get rid from delimiters and other syntax chars.

    For instance, to split a comma-separated list like " A, B ,, C", skip empty values, and trim extra spaces (hence get the above Node list), use a regex like '\s*([^,]+?)\s*(?:,|$)' - a mind twisting one! If instead you want to split the input text by a fixed size (here 10 chars) with the last Item taking whatever remains, use a regex like '(.{10}|.+)' - love it!

    You can then use the function in XSLT 1.0 as follows (quite compact!):

    
        
      
    ...
    

    Executed on a template match yielding the input fragment a, b ,c you'll generate abc

    The trick is not forgetting to follow the function call that generates the Node/Item by the XPath "/Item" (or "/*") as you shall note, so that a Node sequence is returned into the for-each loop.

提交回复
热议问题