vtd-xml

How to trim element name when removing attributes with VTD-XML


Given following xml snippet

<l:Variable xmlns="ddi:instance:3_2" xmlns:g="ddi:group:3_2" xmlns:l="ddi:logicalproduct:3_2" xmlns:r="ddi:reusable:3_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <!-- some more content --!>
</l:Variable>

removing namespace attributes with VTD-XML works well with following snippet:

private String removeNamespaces( String xml )
{
    try
    {
        VTDGen generator = new VTDGen();
        generator.setDoc( xml.getBytes() );
        generator.parse( false );
        VTDNav navigator = generator.getNav();
        XMLModifier xm = new XMLModifier( navigator );
        AutoPilot autoPilot = new AutoPilot( navigator );
        autoPilot.selectXPath( "@*" );
        int i = -1;
        while ((i = autoPilot.evalXPath()) != -1)
        {
            if ( navigator.toString( i ).startsWith( "xmlns" ) )
            {
                xm.removeAttribute( i );
            }
        }
        XMLByteOutputStream xbos = new XMLByteOutputStream( xm.getUpdatedDocumentSize() );
        xm.output( xbos );
        return new String( xbos.getXML() );
    }
    catch (Exception e)
    {
        throw new RuntimeException( e );
    }
}

The result shows the element without the attributes but the blanks between have not be deleted:

<l:Variable     >
    <!-- some more content --!>
</l:Variable>

Usage of navigator.expandWhiteSpaces( l ) et al. does not work because these methods are for elements but not for attributes.

To sum it up: Is it possible to remove attributes to get to a result like

<l:Variable>
    <!-- some more content --!>
</l:Variable>

Solution

  • First of all, I think you can code "starts-with" more concisely in one of the two ways... The first one uses the xpath function of starts-with(). It is technically a xpath 2.0 function, but they are supported in vtd-xml's xpath implementation.. along with contains() and ends-with()...

            generator.parse( false );
            VTDNav navigator = generator.getNav();
            XMLModifier xm = new XMLModifier( navigator );
            AutoPilot autoPilot = new AutoPilot( navigator );
            autoPilot.selectXPath( "@*[starts-with(.,'xmlns')]" );
            int i = -1;
            while ((i = autoPilot.evalXPath()) != -1)
            {
               // if ( navigator.toString( i ).startsWith( "xmlns" ) )
                //{
                    xm.removeAttribute( navigator.trimWhiteSpaces(i) );
                //}
            }
    

    Or you can use VTDNav's startWith,contains or endWith functions directly, instead of explicity bringing a string object into existence (navigator.toString)

    VTDNav navigator = generator.getNav();
            XMLModifier xm = new XMLModifier( navigator );
            AutoPilot autoPilot = new AutoPilot( navigator );
            autoPilot.selectXPath( "@*" );
            int i = -1;
            while ((i = autoPilot.evalXPath()) != -1)
            {
               // if ( navigator.toString( i ).startsWith( "xmlns" ) )
                //{
                if (navigator.startsWith(i, "xmlns"))
                    xm.removeAttribute( i );
                //}
            }
    

    Either way, i think that applying expandWhitespace on an attribute name-value pair segment may be a bit dangerous, since you could remove accidentally the delimiting white spaces and mess up a well-formed xml document...

    Currently, cleaning up the throw-away white spaces is a work-in-progress. I hope it is not a show stopper. If it is, you will have to do it manually... it will be a bit tedious coding. But you will have to

    1. find the start, and end offset of the attribute name value segment

    2. Encoding the start offset and length into a 64-bit integer.

    3. Call trimWhitespace with the right parameters to remove the extraneous white spaces at the end...