javaxmlvtd-xml

How to programmatically create xml with VTD-XML?


I want to create an xml with this shape where I insert the inner elements /a/b in a loop and also set the attributes on element b.

<ROOT>
  <a>
    <b attr1="1" attr2="a"/>
  </a>
  <a>
    <b attr1="1" attr2="b"/>
  </a>
  <a>
    <b attr1="2" attr2="a"/>
  </a>
  <a>
    <b attr1="2" attr2="b"/>
  </a>
</ROOT>

This is the code I have so far:

  public static String createXML(Collection<Integer> numbers, Collection<String> words) {
    String charsetName = "UTF-16";
    byte[] root = "<ROOT></ROOT>".getBytes(charsetName);
    VTDGen vg = new VTDGen();
    AutoPilot ap = new AutoPilot();
    ap.selectXPath("/ROOT");
    XMLModifier xm = new XMLModifier();
    vg.setDoc(root);
    vg.parse(false);
    VTDNav vn = vg.getNav();
    ap.bind(vn);
    xm.bind(vn);

    byte[] aTag = "<a></a>".getBytes(charsetName);
    byte[] bTag = "<b />".getBytes(charsetName);

    int i;

    String collect = numbers.stream().flatMap(number -> words.stream().map(word -> {
      try {
        xm.insertAfterHead(aTag);
        ap.selectXPath("a");
        xm.insertAfterHead(bTag);
        ap.selectXPath("b");
        xm.insertAttribute(String
          .format(" attr1=\"%d\" attr2=\"%s\"",
            number,
            word));
        return xm.outputAndReparse().toNormalizedString(0);
      } catch (ModifyException | NavException | ParseException | IOException | TranscodeException | XPathParseException e) {
        throw new RuntimeException(e);
      }
    }))
      .collect(Collectors.joining(""));

    return collect;
  }

I get a ModifyExcpetion because I call insertAfterHead twice. How can I generate the desired xml shape? I do not fully understand how to put the offset to the right place yet.


Solution

  • I think I may know what you are trying to accomplish. There are a few sugggestions

    Below is my mod of your code.

    public static void main(String[] args) throws VTDException,IOException,
        UnsupportedEncodingException{
            String charsetName = "UTF-16";
            byte[] root = "<ROOT><a><b/></a><a><b/></a><a><b/></a><a><b/></a></ROOT>"
        .getBytes(charsetName); // that is template you want to start with
            VTDGen vg = new VTDGen();
            AutoPilot ap = new AutoPilot();
            ap.selectXPath("/ROOT/a/b");
            XMLModifier xm = new XMLModifier();
            vg.setDoc(root);
            vg.parse(false);
            VTDNav vn = vg.getNav();
            ap.bind(vn);
            xm.bind(vn);
            int i=0;
            int[] ia = new int[4];
            ia[0]=1;ia[1]=1;ia[2]=2;ia[3]=2;
            String[] sa = new String[4];
            sa[0]="a";sa[1]="b";sa[2]="a";sa[3]="b";
            int k=0;
            while((i=ap.evalXPath())!=-1){
                xm.insertAttribute( String.format(" attr1=\"%d\" attr2=\"%s\"",
                        ia[k],
                        sa[k]));
                k++;
            }
            XMLByteOutputStream xbos = new XMLByteOutputStream(xm.getUpdatedDocumentSize());
            xm.output(xbos);
            System.out.println(new String(xbos.getXML(),"UTF-16"));
        }