Error when UPDATING a Tamino-XML-Element

Hi, me again …

I am using the Tamino API4J and want to update an Element in a Tamino-Database.
I select the Element with “TXMLObject xmlObject = response.getFirstXMLObject();” - this works fine.
But when I update the Element with “response = accessor.update(xmlObject);”, I get an error (described further down)

>>>>>>>>>>>>


<<<<<<<<<<<<<<

My Query delivers following output:

xxx
xxx


When I update that with the following:

yxxx
yxxx

I get the following error:

yxxx
yxxx
Access failed:Response could not be built
NestedException:Response could not be built for XML access.
NestedException:Interpreting the input stream for JDOM failed!
NestedException:Error on line 1: Abstandszeichen vor Attributen erforderlich

I have tried typing in the updated text without the nesting node() (), but also only get the same error.

When I enter just text as an update-string, I get the following error:
Update-Error: NestedException:Tamino access failure (INOXDE7711, (cvc-complex-type.2.3): mixed content error, Line 1, Column 35: [content “xxxxxxxxxx” in element “phrase”]) - Only text obviouly doesn’t fit to the schema corresponding to this DOCTYPE.

I have tried all possibilities I can think of - must I possibly enter the update-string different, or must something be changed in the update-code.

I appreciate any help,
thanks,
Rob

Have a nice day,
Rob

Hi Rob,

I have a couple of ideas on this, but perhaps I should start off with a question: what are the values for the parameters “query”, “updatedText” and “encoding”?

I would guess that the value for updatedText is “yxxxyxxx” - is that correct?

If so, I suspect that the problem is that you are replacing the elements “english” and “german” in the “phrase” element with mixed content - which leads to an error.

In the code, the “element” object contains the root node (“phrase”).
I think that if you retrieve the “english” and “german” nodes from element, then call setText(“yzzz”) on them, the update will probably succeeed.

If this doesn’t help, could you please post the schema that you are using?

Greetings,
Trevor.

Hi Trevor!

Thanks for the reply - if I only retrieve the -node in my query and update that to “yxxx”, then I get the following error:
Update-Error: NestedException:Tamino access failure (INOXDE7935, Schema not found)

My Query: /phrase[@ino:id=152]/english
Encoding: ISO-8859-1
Update-String: yxxx

The Output for the above query delivers:
xxx

The Schema easydoesit.tsd:
>>>>>>>>>>>>>>>>>>>

<?xml version = "1.0" encoding = "UTF-8"?>
<xs:schema xmlns:tsd = "http://namespaces.softwareag.com/tamino/TaminoSchemaDefinition" xmlns:xs = "http://www.w3.org/2001/XMLSchema">
  <xs:annotation>
    <xs:appinfo>
      <tsd:schemaInfo name = "easydoesit">
        <tsd:collection name = "easydoesit"></tsd:collection>
        <tsd:doctype name = "phrase">
          <tsd:logical>
            <tsd:content>closed</tsd:content>
          </tsd:logical>
        </tsd:doctype>
        <tsd:adminInfo>
          <tsd:created>2003-03-28T11:44:02.482+01:00</tsd:created>
          <tsd:modified>2003-03-28T11:44:02.482+01:00</tsd:modified>
          <tsd:version>TSD4</tsd:version>
          <tsd:server>4.1.1.1</tsd:server>
        </tsd:adminInfo>
      </tsd:schemaInfo>
    </xs:appinfo>
  </xs:annotation>
  <xs:element name = "phrase">
    <xs:complexType>
      <xs:sequence>
        <xs:element name = "english" type = "xs:string"></xs:element>
        <xs:element name = "german" type = "xs:string"></xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>


<<<<<<<<<<<<<<<<<<<<<<<<<<

Thanks,
Bye, Rob

Hi Rob,

I think I know what the problem is now.
When working with the TXMLAccessor.update() method it is necessary to update the entire document - meaning a full instance of the doctype defined in Tamino.

The error is occurring because there isn’t a doctype corresponding to the “english” element.

If you retrieve the “phrase” document with ino:id=152, modify the text value of its “english” element, then update the [whole] “phrase” document it should work.

You would just need a couple of changes for this:

   ...
   Element element = (Element)xmlObject.getElement();

   // Get the "english" element and update its value
   Element english = element.getChild("english");
   english.setText( updatedText );
   ...
</pre><BR>(The query would also need to be for just <I>/phrase[@ino:id=152]</I> rather than getting the "english" element directly.)<BR><BR>You might also want to have a look at doing the update via an XQuery Update statement:<BR><pre class="ip-ubbcode-code-pre">
   declare namespace tf = "http://namespaces.softwareag.com/tamino/TaminoFunction"
   update replace input()/phrase/english[.="xyyy"]/text()
             with tf:createTextNode("ynot")

(You can update the “english” node directly this way.)

I hope that helps!
Trevor.

Hi Trevor,

The solution with updating the text of the -child while querying the whole phrase-doc, works fine.
But the problem here lies in the detail: I am writing a gui (similar to the Interactive Interface), where many databases can be updated - and I can not know all the subnodes, or which subnodes to update, so I have to stay flexible. It somehow has to be possible to update a whole doc?

I tried the xquery-update too, but got an error back:
XQuery-Error: NestedException:Tamino access failure (INOXME8552, Not a valid request, It is not possible to open a cursor with XQuery Update Request.)

I will play around some more with the API - maybe I find a solution, thanks Trevor,

bye,
Rob

Hi Rob,

I will address the second issue first, because it is easier!
When you are using the XQuery pane of the Interactive Interface, there are two fields which have default values: “Pos. in Result” and “Result size”.
When an XQuery is executed, the values are taken from these fields and are used to open a cursor on the query’s results.
Of course, this doesn’t make any sense for an update statement because there aren’t any results to open a cursor for.
This leads to the error “It is not possible to open a cursor with XQuery Update Request”.

To avoid this, just remove the values from the “Pos. in Result” and “Result Size” fields.

I can see a couple of possibilities for the API update situation. What constraints are placed upon this project - will your GUI only update Tamino databases, or must other systems be supported too?

If you don’t mind the added complexity, you could add a step to pre-process the entered query. Take the query the user enters and execute “enough of it” so that only a whole document is returned to the application.
Then use the “remainder” of the user’s query to break down the returned document(s) for display.

Once the user has made their changes, update the whole document in Tamino…

I hope that helps,
Trevor.

Hi Trevor!

Thanks for the hint. I now have added complexity to my application in the update part (of course I don’t mind :-).
As you suggested, I query just enough of the input-query to successfully update the document afterwards (baseQuery).
Then I want to walk to the most inner node via XPATH, but unfortunately get an Error (which comes from XPATH and JDOM Version 0.9beta, which is available since shortly). I will describe the error after the code-snippet:

>>>>>>>>>>>>>>>>

  public boolean update(TQuery query,String updatedText,String encoding) throws TException  {
    try  {
      // Invoke the query to obtain the document and to lock it
      try { 
          TResponse testresponse = accessor.query(query);
      } catch (Exception e) { return false; }
      
      int startchar = 1;
      String baseQuery = "";
      String restQuery = "";
      char qchar;
      do {
          qchar = query.toString().charAt(startchar);
          if(qchar!='/') { 
              startchar++;
          }
      } while(qchar!='/');
      try { 
          baseQuery = query.toString().substring(0,startchar);
          restQuery = query.toString().substring(startchar+1,query.toString().length()); 
      } catch (Exception e) {}
      System.out.println("\n\nBase:"+baseQuery+"\nRest:"+restQuery+"\nWhole:"+query.toString());
      TResponse response = accessor.query(TQuery.newInstance(baseQuery));
      
      // Obtain the TXMLObject from the response
      TXMLObject xmlObject = response.getFirstXMLObject();
      if ( xmlObject == null )
        return false;
      // Obtain the JDOM element and update its content
      xmlObject.setEncoding(encoding);
      Element element = (Element)xmlObject.getElement();
      if(restQuery.equals("")) {
          element.setText(updatedText);
      } else {
          Element child = null;
          Object ilxp;
          try {
              [B]XPath xpath = XPath.newInstance(restQuery);[/B]
              ListIterator lxp = xpath.selectNodes(xpath).listIterator();
              while(lxp.hasNext()) {
                  ilxp = lxp.next();
                  child = element.getChild((String)ilxp);
              }
              System.out.println("\n\nXPath:"+xpath.getXPath()+"\nChild"+child.toString());
              child.setText(updatedText);
           } catch (Exception e) {}
      }
      // Invoke the update
      xmlObject.writeTo(System.out);
      response = accessor.update(xmlObject);
      
      return true;
    }
    // TQueryException and TUpdateException are both derived from TAccessorException
    // so we simply use the base class here
    catch (TAccessorException accessorException)  {
      showAccessFailure( accessorException );
      throw accessorException;
    }
  }
</pre><BR><<<<<<<<<<<<<<<<<BR><BR>The XML:<BR><BR><pre class="ip-ubbcode-code-pre">
<patient>
 <name>
  <surname>xxx</surname>
  <firstname>yyy</firstname>
 </name>
....
</patient>





The baseQuery, which can be updated is:
/patient[@ino:id=1]

The rest, which I want to walk via XPath: name/surname (if I type in element.getChild(“name”).getChild(“surname”); it works)

Whole:/patient[@ino:id=1]/name/surname

The error I get:

java.lang.NoClassDefFoundError: org/saxpath/SAXPathException
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:140)
at org.jdom.xpath.XPath.newInstance(XPath.java:133)
at TaminoInterface.update(TaminoInterface.java:139)
at TaminoInterface.update(TaminoInterface.java:165)
at TaminoCom.bUpdateActionPerformed(TaminoCom.java:446)
at TaminoCom.access$300(TaminoCom.java:26)
at TaminoCom$4.actionPerformed(TaminoCom.java:186)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1764)
at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1817)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:419)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:257)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:245)
at java.awt.Component.processMouseEvent(Component.java:5093)
at java.awt.Component.processEvent(Component.java:4890)
at java.awt.Container.processEvent(Container.java:1566)
at java.awt.Component.dispatchEventImpl(Component.java:3598)
at java.awt.Container.dispatchEventImpl(Container.java:1623)
at java.awt.Component.dispatchEvent(Component.java:3439)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3450)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3165)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3095)
at java.awt.Container.dispatchEventImpl(Container.java:1609)
at java.awt.Window.dispatchEventImpl(Window.java:1585)
at java.awt.Component.dispatchEvent(Component.java:3439)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:450)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:197)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:144)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:136)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)

After the easter-weekend I will check out the error,
bye and have a nice weekend,
Rob

Hi Rob,

this is starting to look pretty good!

The reason for the NoClassDefFoundError is that you probably do not have the saxpath.jar file in your classpath. Once I added that to mine, the error changed.
You will also need to add the jaxen-core.jar and jaxen-jdom.jar files to your classpath in order to run.

I had to make a couple of small tweaks, but then it worked correctly.
(I have marked the changes I made with “TFO”.)

I hope you have (or had!) a great Easter weekend,
Trevor.

  public boolean update(TQuery query,String updatedText,String encoding) throws TException  {
    try  {
      // Invoke the query to obtain the document and to lock it
      try { 
          TResponse testresponse = accessor.query(query);
      } catch (Exception e) { return false; }
      
      int startchar = 1;
      String baseQuery = "";
      String restQuery = "";
      char qchar;
      do {
          qchar = query.toString().charAt(startchar);
          if(qchar!='/') { 
              startchar++;
          }
      } while(qchar!='/');
      try { 
          baseQuery = query.toString().substring(0,startchar);
          restQuery = query.toString().substring(startchar+1,query.toString().length()); 
      } catch (Exception e) {}
      System.out.println("\n\nBase:"+baseQuery+"\nRest:"+restQuery+"\nWhole:"+query.toString());
      TResponse response = accessor.query(TQuery.newInstance(baseQuery));
      
      // Obtain the TXMLObject from the response
      TXMLObject xmlObject = response.getFirstXMLObject();
      if ( xmlObject == null )
        return false;
      // Obtain the JDOM element and update its content
      xmlObject.setEncoding(encoding);
      Element element = (Element)xmlObject.getElement();
      if(restQuery.equals("")) {
          element.setText(updatedText);
      } else {
          Element child = null;
	  // TFO Object ilxp;
          try {
              XPath xpath = XPath.newInstance(restQuery);
	      // TFO: use the xpath object to select nodes from the element object
	      ListIterator lxp = xpath.selectNodes(element).listIterator();

              while(lxp.hasNext()) {
                  // TFO ilxp = lxp.next();
                  // TFO child = element.getChild((String)ilxp);
                  // TFO: the child we need is (hopefully) the first one in the Iterator
                  child = (Element)lxp.next();
              }
              System.out.println("\n\nXPath:"+xpath.getXPath()+"\nChild"+child.toString());

	      // TFO: if there is a child element, set its text value
	      if ( child != null ) {
                  child.setText(updatedText);
	      }
	      else {
                  // TFO: if there isn't a child element, tell someone...
                  System.out.println("Child IS NULL");
                  return false;
	      }
           } catch (Exception e) {}
      }
      // Invoke the update
      xmlObject.writeTo(System.out);
      response = accessor.update(xmlObject);
      
      return true;
    }
    // TQueryException and TUpdateException are both derived from TAccessorException
    // so we simply use the base class here
    catch (TAccessorException accessorException)  {
        showAccessFailure( accessorException );
        throw accessorException;
    }

    return false;  // TFO
  }

Hi Trevor!

Thanks, that worked fine - the problem is solved.

Bye,
Rob :smiley: