العمل باستخدام النطاقات المُعنونة

تتيح لك Google Docs API استخدام النطاقات المُسمّاة لتبسيط بعض مهام التعديل.

عند إنشاء نطاق مُعنوَن، يمكنك تحديد قسم من المستند يمكنك الرجوع إليه لاحقًا. يتم تعديل فهارس النطاق المُعنوَن تلقائيًا عند إضافة محتوى إلى المستند وإزالته منه. يسهّل ذلك عملية تحديد مكان النص المطلوب تعديله في المستقبل، لأنّك لن تحتاج إلى تتبُّع التغييرات التي تم إجراؤها على النص أو البحث في المستند. بدلاً من ذلك، يمكنك الحصول على تعديل الموقع من خلال قراءة النطاق المُعنوَن واستخدام فهارسه.

على سبيل المثال، لنفترض أنّك أنشأت نطاقًا مُعنوَنًا يجب أن تظهر فيه سلسلة "وصف المنتج" في مستند:

يتيح لك ذلك استبدال الوصف: ما عليك سوى الحصول على فهرسَي البدء والانتهاء للنطاق المُعنوَن، ثم تعديل النص بين هذين الفهرِسين باستخدام المحتوى الجديد.

يوضّح مثال الرمز البرمجي التالي كيفية تنفيذ دالة مساعدة ل replacement محتويات نطاق مُعنوَن في علامة التبويب الأولى من المستند، حيث تم إنشاء النطاق المُعنوَن سابقًا باستخدام دالة CreateNamedRangeRequest. لاستبدال النطاقات المُسمّاة من جميع علامات التبويب، يمكن تحسين هذا الرمز البرمجي للتكرار في جميع علامات التبويب. اطّلِع على العمل مع علامات التبويب للحصول على مزيد من المعلومات ونماذج الرموز البرمجية.

Java

/** Replaces the text in existing named ranges. */
static void replaceNamedRange(Docs service, String documentId, String rangeName, String newText)
    throws IOException {
  // Fetch the document to determine the current indexes of the named ranges.
  Document document =
      service.documents().get(documentId).setIncludeTabsContent(true).execute();

  // Find the matching named ranges in the first tab of the document.
  NamedRanges namedRangeList =
      document.getTabs()[0].getDocumentTab().getNamedRanges().get(rangeName);
  if (namedRangeList == null) {
    throw new IllegalArgumentException("The named range is no longer present in the document.");
  }

  // Determine all the ranges of text to be removed, and at which indexes the replacement text
  // should be inserted.
  List<Range> allRanges = new ArrayList<>();
  Set<Integer> insertIndexes = new HashSet<>();
  for (NamedRange namedRange : namedRangeList.getNamedRanges()) {
    allRanges.addAll(namedRange.getRanges());
    insertIndexes.add(namedRange.getRanges().get(0).getStartIndex());
  }

  // Sort the list of ranges by startIndex, in descending order.
  allRanges.sort(Comparator.comparing(Range::getStartIndex).reversed());

  // Create a sequence of requests for each range.
  List<Request> requests = new ArrayList<>();
  for (Range range : allRanges) {
    // Delete all the content in the existing range.
    requests.add(
        new Request().setDeleteContentRange(new DeleteContentRangeRequest().setRange(range)));

    if (insertIndexes.contains(range.getStartIndex())) {
      // Insert the replacement text.
      requests.add(
          new Request()
              .setInsertText(
                  new InsertTextRequest()
                      .setLocation(
                          new Location()
                              .setSegmentId(range.getSegmentId())
                              .setIndex(range.getStartIndex())
                              .setTabId(range.getTabId()))
                      .setText(newText)));

      // Re-create the named range on the new text.
      requests.add(
          new Request()
              .setCreateNamedRange(
                  new CreateNamedRangeRequest()
                      .setName(rangeName)
                      .setRange(
                          new Range()
                              .setSegmentId(range.getSegmentId())
                              .setStartIndex(range.getStartIndex())
                              .setEndIndex(range.getStartIndex() + newText.length())
                              .setTabId(range.getTabId()))));
    }
  }

  // Make a batchUpdate request to apply the changes, ensuring the document hasn't changed since
  // we fetched it.
  BatchUpdateDocumentRequest batchUpdateRequest =
      new BatchUpdateDocumentRequest()
          .setRequests(requests)
          .setWriteControl(new WriteControl().setRequiredRevisionId(document.getRevisionId()));
  service.documents().batchUpdate(documentId, batchUpdateRequest).execute();
}

Python

def replace_named_range(service, document_id, range_name, new_text):
    """Replaces the text in existing named ranges."""

    # Determine the length of the replacement text, as UTF-16 code units.
    # https://developers.google.com/docs/api/concepts/structure#start_and_end_index
    new_text_len = len(new_text.encode('utf-16-le')) / 2

    # Fetch the document to determine the current indexes of the named ranges.
    document = (
        service.documents()
        .get(documentId=document_id, includeTabsContent=True)
        .execute()
    )

    # Find the matching named ranges in the first tab of the document.
    named_range_list = (
        document.get('tabs')[0]
        .get('documentTab')
        .get('namedRanges', {})
        .get(range_name)
    )
    if not named_range_list:
        raise Exception('The named range is no longer present in the document.')

    # Determine all the ranges of text to be removed, and at which indices the
    # replacement text should be inserted.
    all_ranges = []
    insert_at = {}
    for named_range in named_range_list.get('namedRanges'):
        ranges = named_range.get('ranges')
        all_ranges.extend(ranges)
        # Most named ranges only contain one range of text, but it's possible
        # for it to be split into multiple ranges by user edits in the document.
        # The replacement text should only be inserted at the start of the first
        # range.
        insert_at[ranges[0].get('startIndex')] = True

    # Sort the list of ranges by startIndex, in descending order.
    all_ranges.sort(key=lambda r: r.get('startIndex'), reverse=True)

    # Create a sequence of requests for each range.
    requests = []
    for r in all_ranges:
        # Delete all the content in the existing range.
        requests.append({
            'deleteContentRange': {
                'range': r
            }
        })

        segment_id = r.get('segmentId')
        start = r.get('startIndex')
        tab_id = r.get('tabId')
        if insert_at[start]:
            # Insert the replacement text.
            requests.append({
                'insertText': {
                    'location': {
                        'segmentId': segment_id,
                        'index': start,
                        'tabId': tab_id
                    },
                    'text': new_text
                }
            })
            # Re-create the named range on the new text.
            requests.append({
                'createNamedRange': {
                    'name': range_name,
                    'range': {
                        'segmentId': segment_id,
                        'startIndex': start,
                        'endIndex': start + new_text_len,
                        'tabId': tab_id
                    }
                }
            })

    # Make a batchUpdate request to apply the changes, ensuring the document
    # hasn't changed since we fetched it.
    body = {
        'requests': requests,
        'writeControl': {
            'requiredRevisionId': document.get('revisionId')
        }
    }
    service.documents().batchUpdate(documentId=document_id, body=body).execute()

تجدر الإشارة إلى أنّ النطاقات المُسمّاة تحدِّد نطاقًا من محتوى المستند، ولكنها ليست جزءًا من هذا المحتوى. إذا استخرجت محتوى يتضمّن نطاقًا مُعنوَنًا، ثم أدرجته في موقع آخر، يشير النطاق المُعنوَن إلى المحتوى الأصلي فقط وليس القسم المُكرّر.