Shoutbox

[Help] Enumerating XML nodes... - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: [Help] Enumerating XML nodes... (/showthread.php?tid=92940)

[Help] Enumerating XML nodes... by whiz on 11-16-2009 at 07:14 PM

Okay, here's a sample window, written through my Interface Writer.

xml code:
<Interfaces xmlns="urn:msgplus:interface" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:msgplus:interface PlusInterface.xsd">

<!-- Written using Interface Writer 2.2 by WhizWeb Community -->

<Window Id="WndTest" Version="1">

    <Attributes>
        <Caption>Test Window</Caption>
    </Attributes>

    <TitleBar>
        <AllowMaximize>true</AllowMaximize>
        <Title>
            <Prefix>Image</Prefix>
            <Text>Test Window</Text>
        </Title>
    </TitleBar>

    <Position Width="400" Height="300" InitialPos="Random">
        <IsAbsolute>true</IsAbsolute>
        <Resizeable Allowed="BothSides">
            <MinWidth>400</MinWidth>
            <MinHeight>300</MinHeight>
        </Resizeable>
    </Position>

    <WindowTmpl/>

    <Controls>
        <Control xsi:type="RichEditControl" Id="EdtMain">
            <Position Left="3" Top="0" Width="380" Height="223">
                <Units>AllPixels</Units>
                <Anchor Horizontal="LeftRightFixed" Vertical="TopBottomFixed"/>
            </Position>
        </Control>
        <Control xsi:type="ButtonControl" Id="BtnOk">
            <Position Left="3" Top="228" Width="100">
                <Units>AllPixels</Units>
                <Anchor Vertical="BottomFixed"/>
            </Position>
            <Image>
                <Name>sounds-check</Name>
            </Image>
            <Caption>&amp;Ok</Caption>
        </Control>
        <Control xsi:type="ButtonControl" Id="BtnCancel">
            <Position Left="283" Top="228" Width="100">
                <Units>AllPixels</Units>
                <Anchor Horizontal="RightFixed" Vertical="BottomFixed"/>
            </Position>
            <Image>
                <Name>icon-delete</Name>
            </Image>
            <Caption>&amp;Cancel</Caption>
        </Control>
    </Controls>

</Window>

</Interfaces>
I don't know if it's possible, but what I would like to do is enumerate the nodes within Interface/Window/Controls/Control.  For the ones that aren't supported directly (i.e. not position, caption or help), I would like to be able to grab the code.  For example, say I have a variable called ControlExtra.
xml code:
<Control xsi:type="ButtonControl" Id="BtnOk">
    <Position Left="3" Top="228" Width="100">
        <Units>AllPixels</Units>
        <Anchor Vertical="BottomFixed"/>
    </Position>
>>>    <Image><<<
>>>        <Name>sounds-check</Name><<<
>>>    </Image><<<
    <Caption>&amp;Ok</Caption>
</Control>
I need the script to find the highlighted lines, because they're not recognized elements.  I then need the variable to store all of the code (including nodes), like this below.
code:
<Image>
    <Name>sounds-check</Name>
</Image>
Is this possible?
RE: [Help] Enumerating XML nodes... by matty on 11-16-2009 at 07:27 PM

This is code from Screenshot Sender to enumerate controls it could be altered to do what you would need it to do:

js code:
/*
    Name:     EnumControls
    Purpose:    Enum the controls from a specified window
    Parameters: File - The name of the file
             pPlusWnd - The Plus! window object
    Return:     None
*/
function EnumControls ( File , pPlusWnd ) {
    _debug.getfuncname ( arguments ) ;
    // Load the XML from the specified file
    var XML = new ActiveXObject ( 'MSXML.DOMDocument' ) ;
    XML.load ( File ) ;
    // Loop through all of the controls
    var Controls = XML.selectNodes ( '/Interfaces/Window [ @Id='' + pPlusWnd.WindowId + '' ] /Controls/Control' ) ;
    for ( i=0 ; i<Controls.length ; i ++) {
        var Id = Controls [ i ].getAttribute ( 'Id' ) ;
        var Type = Controls [ i ].getAttribute ( 'xsi:type' ) ;
        // Get the value depending on the control's type
        objControls [ Id ] = {} ;
        objControls [ Id ].XsiType = Type ;
        objControls [ Id ].Value = pPlusWnd_GetControlvalue ( pPlusWnd , Id , Type ) ;
    }
}

RE: [Help] Enumerating XML nodes... by whiz on 11-16-2009 at 07:36 PM

quote:
Originally posted by matty
This is code from Screenshot Sender to enumerate controls it could be altered to do what you would need it to do:

js code:
/*
    Name:     EnumControls
    Purpose:    Enum the controls from a specified window
    Parameters: File - The name of the file
             pPlusWnd - The Plus! window object
    Return:     None
*/
function EnumControls ( File , pPlusWnd ) {
    _debug.getfuncname ( arguments ) ;
    // Load the XML from the specified file
    var XML = new ActiveXObject ( 'MSXML.DOMDocument' ) ;
    XML.load ( File ) ;
    // Loop through all of the controls
    var Controls = XML.selectNodes ( '/Interfaces/Window [ @Id='' + pPlusWnd.WindowId + '' ] /Controls/Control' ) ;
    for ( i=0 ; i<Controls.length ; i ++) {
        var Id = Controls [ i ].getAttribute ( 'Id' ) ;
        var Type = Controls [ i ].getAttribute ( 'xsi:type' ) ;
        // Get the value depending on the control's type
        objControls [ Id ] = {} ;
        objControls [ Id ].XsiType = Type ;
        objControls [ Id ].Value = pPlusWnd_GetControlvalue ( pPlusWnd , Id , Type ) ;
    }
}

That loops through all of the controls, but I need it to loop through all the children of the controls.  The problem I have is that some nodes, like the <Image> node, store their data in another child, meaning that I have to do a loop in a loop, in a loop, and so on.

Obviously, I can only go so far, and I'd rather just have the entire code, but I don't think that can be done, unless I don't use the XML DOM, and start checking each line through the FileSystemObject.  But that's a bit ridiculous.  :S

EDIT: Done it now.  Ended up using the nodeObj.xml property, and filtering out the recognized bits.  Perhaps not the best method, but it works.  :P
js code:


RE: [Help] Enumerating XML nodes... by Matti on 11-17-2009 at 06:42 PM

You could use some recursion for that. :P
The following code should enumerate all windows and all controls in those windows and all the children in those controls. Accessing such an element could then be done like this:

js code:
var Windows = EnumWindows("Interfaces.xml");
var ImageName = Windows["WndTest"].Controls["BtnOk"].Children["Image"].Name.Text;
Debug.Trace(ImageName);
WARNING! Untested code! Try it out and tell me whether it works.
js code:
/*
    Enumerates all windows in a file with all their controls
*/

var objWindows = { } ;

function EnumWindows ( File ) {
    // Load the XML from the specified file
    var XML = new ActiveXObject ( 'MSXML.DOMDocument' ) ;
    XML.async = false ;
    XML.load ( File ) ;
    // Loop through all of the windows
    var Windows = XML.selectNodes ( '/Interfaces/Window' ) ;
    for ( var i=0 ; i<Windows.length ; i ++) {
        // Get the current window
        var Node = Windows [ i ] ;
        // Create a new object
        var objWindow = { } ;
        objWindow.Id = Node.getAttribute ( 'Id' ) ;
        objWindow.Controls = EnumControls( Node ) ;
        // Add to collection
        objWindows [ Id ] = objWindow;
    }
    // Return all windows
    return objWindows ;
}

function EnumControls ( Window ) {
    var objControls = { } ;
    // Loop through all of the controls
    var Controls = Window.selectNodes ( '/Controls/Control' ) ;
    for ( var i=0 ; i<Controls.length ; i ++) {
        // Get the current control
        var Node = Controls [ i ] ;
        var Id = Node.getAttribute ( 'Id' ) ;
        var Type = Node.getAttribute ( 'xsi:type' ) ;
        // Create a new object
        var objControl = { } ;
        objControl.Id = Id ;
        objControl.XsiType = Type ;
        if( Node.hasChildNodes() ) objControl.Children = EnumControlChildren ( Node ) ;
        // Add to collection
        objControls [ Id ] = objControl ;
    }
    // Return collected controls
    return objControls ;
}

function EnumControlChildren( Node ) {
    objChildren = { } ;
    // Loop through all of the children
    var Children = Node.childNodes ;
    for( var i=0; i<Children.length; i ++) {
        // Get the current child
        var Child = Controls [ i ] ;
        var NodeName = Child.nodeName ;
        // Create a new object
        var objChild = { } ;
        objChild.TagName = Child.nodeName;
        // Enumerate all attributes
        var Attrs = Child.attributes;
        for( var j=0 ; j<Attrs.length ; j ++) {
            var Attr = Attrs [ j ] ;
            objChild [ Attr.name ] = Attr.text ;
        }
        // Enumerate all children through recursion
        if( Child.hasChildNodes() ) objChild.Children = EnumControlChildren ( Child ) ;
        else objChild.Text = Node.text;
        // Add to collection
        var NodeId = Child.getAttribute ( 'Id' ) ;
        if(NodeId !== null) objChildren [ NodeId ] = objChild ;
        else objChildren [ NodeName ] = objChild ;
    }
    // Return collected children
    return objChildren ;
}

RE: [Help] Enumerating XML nodes... by matty on 11-17-2009 at 07:08 PM

Looks good Matti... but shouldn't you be working on something else :P


RE: [Help] Enumerating XML nodes... by whiz on 11-18-2009 at 03:22 PM

I can't test it at the moment, but I'll try it tomorrow.  :)