PHP API - Inserting a new document field

I have a word document with multiple paragraphs. I’d like to insert a field code at the begining of the first paragraph.

$paragraph_index = 0;

$wordsApi->insertField(
new InsertFieldRequest(
		$filename,          // The filename of the input document.
		new FieldInsert([
			"field_code" => "{ TC \"Text Entry\" }",
		]),                 // \Aspose\Words\Model\FieldInsert $field Field data.
		"sections/0/paragraphs/$paragraph_index",   // The path to the node in the document tree.
		$folder,            // Original document folder.
		$storage,           // Original document storage.
		insert_before_node: $paragraph_index // The index of the node. A new field will be inserted before the node with the specified node Id.                                                            
));

When I try this I get the following error:
“Error: InsertField. Exception: Value cannot be null. (Parameter ‘node’).”

If I exclude the insert_before_node parameter it works - but the field is inserted at the end of the paragraph (which is not what I want).

What value shoudl I be using for insert_before_node ?

@FFSPUD

We are looking into it and will guide you accordingly.

@FFSPUD

Thanks for your patience. You need to pass the nodeid in the insertbeforenode parameter. For example, if you pass the paragraph path in the nodepath parameter, then insertbeforenode operates with the runs inside the paragraph as follows:

nodepath: sections/0/body/paragraphs/0
insertbeforenode: 0.0.0.0

Hello, thank for your response.

I’m still having difficulty trying to construct the correct path and node Id.
In the attached document I am trying to insert a field before each occurence of the {{_page_number_}} text.

I am using the search function successfully to return ranges for each occurence of the text:

{
    "SearchingPattern": "{{_page_number_}}",
    "SearchResults": {
        "ResultsList": [
            {
                "RangeEnd": {
                    "Node": {
                        "NodeId": "0.0.5.0.2.1.0"
                    },
                    "Offset": 17
                },
                "RangeStart": {
                    "Node": {
                        "NodeId": "0.0.5.0.2.1.0"
                    },
                    "Offset": 0
                }
            },
            {
                "RangeEnd": {
                    "Node": {
                        "NodeId": "0.0.5.1.2.0.0"
                    },
                    "Offset": 17
                },
                "RangeStart": {
                    "Node": {
                        "NodeId": "0.0.5.1.2.0.0"
                    },
                    "Offset": 0
                }
            },
            {
                "RangeEnd": {
                    "Node": {
                        "NodeId": "0.0.5.2.2.0.0"
                    },
                    "Offset": 17
                },
                "RangeStart": {
                    "Node": {
                        "NodeId": "0.0.5.2.2.0.0"
                    },
                    "Offset": 0
                }
            },
            {
                "RangeEnd": {
                    "Node": {
                        "NodeId": "0.0.5.3.2.0.0"
                    },
                    "Offset": 17
                },
                "RangeStart": {
                    "Node": {
                        "NodeId": "0.0.5.3.2.0.0"
                    },
                    "Offset": 0
                }
            }
        ]
    },
    "RequestId": "Root=1-6454d567-4ac9d8010cb153ea02e0b30a"
}

However when I try to insert a field I get the following error:

Error: InsertField. Exception: Exception has been thrown by the target of an invocation. => Object with index 1 not found…

I am using:
nodePath: sections/0/body/tables/5/rows/0/cells/2/paragraphs/1
insertBeforeNode: 0.0.5.0.2.1.0

As these values have been returned by the search api call I would have expected them to work - what am I doing wrong?

Insertfield.docx (17.8 KB)

@FFSPUD

Please share your sample code to search the text. I am getting different nodeid for the page number fields in your shared document using the Paragraph API and Search API.

Hello.

My mistake - I had stripped out some pages from the document for upload. I have attached the original document and my code:

doc0.docx (13.8 KB)

        $folder   = "/test";
        $storage  = "TEST";        
        $filename = "doc0.docx";

        //find the page number placeholders
        $searchResponse = $wordsApi->search(
                                                new SearchRequest(
                                                    $filename,
                                                    '{{_page_number_}}',
                                                    $folder,
                                                    $storage
                                            ));

        $searchResult = $searchResponse->getSearchResults()->getResultsList()[0];
        $documentPosition = $searchResult->getRangeStart();
        $nodeId = $documentPosition->getNode()->getNodeId();
        $path = 'sections/0/body/tables/5/rows/0/cells/2/paragraphs/1';

        //insert tc field
        $wordsApi->insertField(
            new InsertFieldRequest(
                    $filename,
                    new FieldInsert([
                        "field_code" => "{ TC \"$nodeId\" }",
                    ]),
                    $path,
                    $folder,
                    $storage,
                    insert_before_node: $nodeId
            )
        );

@FFSPUD

Thanks for sharing the updated document. Are you still having issues with it? As I have tried to insert a field { TC “$nodeId” } before the first occurrence of {{page_number}} and have been unable to notice the issue.

nodePath: sections/0/body/tables/1/rows/0/cells/2/paragraphs/1
InsertBeforeNode: 0.0.5.0.2.1.0

I see where I went wrong.
I had assumed the correct path for the nodeID parameter would be the one returned by the search function e.g.
nodePath: sections/0/body/tables/ 5 /rows/0/cells/2/paragraphs/1
InsertBeforeNode: 0.0.5.0.2.1.0

But it seems, as per your working example, that this is not the case.
It would appear that unless you know the structure of the document you can’t use nodeIds returned by the search function as paths.

It would be useful if there was an function that given a nodeId would return what type of node it is and what its index is: e.g.

$response = $wordsApi->whatTypeofNodeIsThis('0.0.5');
echo $response->getNodeType();
echo $response->getNodeIndex();

> Table
> 1

But I’m guessing from my previous post on the subject that this isn’t the case?

Continuing my previous reply; If there is no way to programmatically discover the structure of the document then this severly restricts how I can use the API functions.

For instance, if I have a document structured like this:

"Paragraph A"

[ A Table ]

[Another Table]

"Paragraph B"

If I search for the text “Paragraph” the API should tell me the text was found in nodes 0.0.0 and 0.0.3.

However in order to get “Paragraph B” using the API - I need to know it’s it’s node path which is sections/0/body/paragraphs/2.

I only know the index to use for the paragraph becuase I know the structure of the document - it can’t be ‘calculated’ from the node id returned from the search function.

This means I can only modify documents I’ve built where I’ve dictated the structure programatically.

Is this correct?

@FFSPUD

Please check whether the following API method fulfils your requirement, as you do not need to pass the nodePath but only the insertBeforeNode index. Otherwise, we will log a ticket for the solution to your requirement.

POST ​/words​/{name}​/fields Inserts a new field to the document node without NodePath.

That would solve my problem when inserting fields thanks!

I can’t find similar api calls for runs, table rows or cells though - the closest I could find were these and they all require paths:

POST​/words​/{name}​/{paragraphPath}​/runs Inserts a new Run object to the paragraph.
POST​/words​/{name}​/{tablePath}​/rows Inserts a new row to the table.
POST​/words​/{name}​/{tableRowPath}​/cells Inserts a new cell to the table row.

Also there doesn’t appear to be any way of getting the nodeId or path for any bookmarks in the document.

If I could log a ticket for an api call to convert a nodeId to a path I’m sure other people would find it useful - certainly from a debugging point of view.

@FFSPUD

Thanks for sharing the details. We are investigating it and will guide you accordingly.

A post was split to a new topic: How to Delete Document Nodes via NodeId?

@FFSPUD

We have logged a feature request(WORDSCLOUD-2329) to translate the NodeId to the NodePath. We will notify you as soon as it is resolved.

@FFSPUD

Please confirm which kind of API call you need to insert these nodes(runs/rows/cells/bookmark) into a document: InsertFieldWithoutNodePath or InsertField. So we will log feature requests accordingly.

I think the new APIs call should work like InsertFieldWithoutNodePath

E.g.

POST /words/{name}/runs

Name Description
name *

string

(path)|The filename of the input document.|
|folder

string

(query)|Original document folder.|
|storage

string

(query)|Original document storage.|
|loadEncoding

string

(query)|Encoding that will be used to load an HTML (or TXT) document if the encoding is not specified in HTML.|
|password

string

(query)|Password of protected Word document. Use the parameter to pass a password via SDK. SDK encrypts it automatically. We don’t recommend to use the parameter to pass a plain password for direct call of API.|
|encryptedPassword

string

(query)|Password of protected Word document. Use the parameter to pass an encrypted password for direct calls of API. See SDK code for encyption details.|
|destFileName

string

(query)|Result path of the document after the operation. If this parameter is omitted then result of the operation will be saved as the source document.|
|revisionAuthor

string

(query)|Initials of the author to use for revisions.If you set this parameter and then make some changes to the document programmatically, save the document and later open the document in MS Word you will see these changes as revisions.|
|revisionDateTime

string

(query)|The date and time to use for revisions.|
|insertBeforeNode

string

(query)|The index of the node. A new field will be inserted before the node with the specified node Id.|

Request body

Run data.

Example Value
Schema

{
“Text”: “string”
}

It would be very useful if the API calls also supported a ‘InsertAfterNode’ parameter so that new runs/rows/cells can be appended to existing nodes.

Ideally this new parameters could also be applied to the existing InsertParagraphWithoutNodePath and InsertTableWithoutNodePath calls.

@FFSPUD

We have logged a ticket (WORDSCLOUD-2333) to insert nodes(runs/rows/cells/bookmark) into a Word document using InsertBeforeNode without NodePath. We will keep you updated about the issue resolution progress within this forum thread.

@FFSPUD

We have logged a feature request (WORDSCLOUD-2334) for the support of InsertAfterNode parameter in insert APIs. We will keep you updated about the issue resolution progress within this forum thread.

The issues you have found earlier (filed as WORDSCLOUD-2333) have been fixed in this update. This message was posted using Bugs notification tool by Ivanov_John