insert method in ElementTree

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • mirandacascade@yahoo.com

    #1

    insert method in ElementTree

    O/S: Win2K
    Vsn of Python: 2.4

    Example:

    <a>
    <b createAnotherWh enCondition="x" >
    <c>text for c</c>
    <d>text for d</d>
    </b>
    <e>
    <f>text for f</f>
    <g>text for g</g>>
    </e>
    <h>
    <i>text for i</i>
    <j createAnotherWh enCondition="y" >
    <k>text for k</k>
    <l>text for l</l>
    </j>
    <m>text for m</m>
    </h>
    </a>

    Python script reads XML document above into ElementTree. The script
    outputs an XML document that is based on the XML document above. The
    output XML will contain all of the elements in the XML document above.
    If there is a parent element that does not have the
    createAnotherWh encondition attribute, then that element and its
    descendants will be part of the output XML. If there is a parent
    element with atribute createAnotherWh enCondition and that condition is
    true, then the output XML should contain another instance of the parent
    element below the original instance. For example if x were true when
    the script ran, the output XML document would be:

    <a>
    <b>
    <c>text for c</c>
    <d>text for d</d>
    </b>
    <b>
    <c>text for c</c>
    <d>text for d</d>
    </b>
    <e>
    <f>text for f</f>
    <g>text for g</g>>
    </e>
    <h>
    <i>text for i</i>
    <j>
    <k>text for k</k>
    <l>text for l</l>
    </j>
    <m>text for m></m>
    </h>
    </a>

    The example attempts to illustrate that the createAnotherWh enCondition
    attribute may appear in parent elements that are at different levels in
    the hierarchy; the <belement is at the 2nd level in the hierarchy,
    and the <jelement is at the 3rd level. There will never be
    'nesting', i.e. a parent element with the
    createAnotherWh enCondition attribute that is a descendant of a parent
    element with a createAnotherWh enCondition attribute.

    I'm pretty sure I can figure out how to create the output XML by
    creating a second XML document. It would be created by iterating
    through the input XML. When a new element is encountered, an element
    or subelement would be created in the output XML. When a parent
    element with the createAnotherWh enCondition is encountered and that
    condition is true, I think I can figure out how to propagate another
    instance of that parent element and all its descendants.

    My request for advice is this: instead of creating a second XML
    document that represents the output, would it be possible to expand the
    input XML document as needed? I was thinking that the program could
    iterate through all the elements. As it is iterating, it would check
    for the createAnotherWh enCondition attribute. If encountered and if
    the condition were true, the program would:
    - make a copy of the parent element (perhaps with copy.copy)
    - use the insert method to insert the just-created copy
    Where I'm struggling is figuring out what the index argument should
    be in the insert method. Using the example above

    # assume rootElement is the root of the input XML
    xList = rootElement.get iterator()
    idx = 0
    for x in xList:
    # mix of pseudo-code and Python code
    if (this element has createAnotherWh enCondition attribute)
    and
    (y is true):
    jcopy = copy.copy(x)
    ??.insert(??, jcopy)
    idx = idx + 1

    If the program were run when y was true, then I believe it would
    encounter the <jelement when idx has a value of 9. Conceptually, I
    think that jcopy should be inserted after the <jelement and before
    the <melement. But I'm not sure that 9 (the index in the list
    created from rootElement.get iterator()) has any relevance for this
    insert task. Assuming that I want to insert jcopy after the <j>
    element and before the <melement:
    a) would the insert need to be done relative to the <helement, which
    is the parent of <j>
    b) if so, would the index argument in the insert method be relative
    index within the <helement?

  • Stefan Behnel

    #2
    Re: insert method in ElementTree

    mirandacascade@ yahoo.com wrote:
    Where I'm struggling is figuring out what the index argument should
    be in the insert method. Using the example above
    >
    # assume rootElement is the root of the input XML
    xList = rootElement.get iterator()
    idx = 0
    for x in xList:
    # mix of pseudo-code and Python code
    if (this element has createAnotherWh enCondition attribute)
    and
    (y is true):
    jcopy = copy.copy(x)
    ??.insert(??, jcopy)
    idx = idx + 1
    ElementTree does not have parent pointers. You have to look one element level
    ahead to add the child. You can use a parent stack for this, although
    getiterator() is not very helpful in that case as it does not tell you when it
    backtracks.

    If you want to use lxml instead, you can either
    * access the parent directly (element.getpar ent()) and add the child there
    or
    * use the iterwalk() function to add the child when backtracking up the tree or
    * implement the whole thing in XSLT (with a custom evaluator function in Python).

    There may also be other ways to do it. Just give it a try:



    Stefan

    Comment

    • Carl Banks

      #3
      Re: insert method in ElementTree

      mirandacascade@ yahoo.com wrote:
      My request for advice is this: instead of creating a second XML
      document that represents the output, would it be possible to expand the
      input XML document as needed? I was thinking that the program could
      iterate through all the elements. As it is iterating, it would check
      for the createAnotherWh enCondition attribute. If encountered and if
      the condition were true, the program would:
      - make a copy of the parent element (perhaps with copy.copy)
      - use the insert method to insert the just-created copy
      Where I'm struggling is figuring out what the index argument should
      be in the insert method.
      I recommend not using the insert method; instead, build a new list of
      elements and set the parent to the new list. Another problem is that
      you have to have the parent node around, since children don't indicate
      their parents. Using getiterator won't work. I recommend a recursive
      function instead. Something like this should do it:

      def expand_children (parent):
      if len(parent) == 0:
      return
      newchildren = []
      for child in parent:
      expand_children (child) # recursively process child nodes
      if <you're supposed to create another child>:
      <remove createAnotherWh enCondition attr>
      newchildren.app end(child) # or copy.copy(child )
      newchildren.app end(child)
      parent[:] = newchildren # slice assign

      So, basically, for each node, you build a list of children in parallel,
      making duplicates as necessary, then use slice assignment to set the
      parent's children to be the new list. No more mucking around with
      indexes.


      Carl Banks

      Comment

      Working...