💡 Ví dụ hoạt động đầy đủ có trên GitHub:
office-metadata-pii-cleanup-nodejs

Giới thiệu

Một endpoint tải lên nhận một tệp DOCX từ nhân viên và lưu nó vào vé của khách hàng. Văn bản không có vấn đề. Các thuộc tính lại có: tệp ghi tên người soạn, đồng nghiệp người lưu lần cuối, quản lý bộ phận từ mẫu công ty, và vì nó được lấy từ SharePoint nên còn có người phê duyệt đã ký duyệt.

Một công cụ làm sạch metadata là một script nhỏ xóa các thuộc tính đó trước khi tệp được lưu và sau đó kiểm tra lại công việc của mình. Hướng dẫn này xây dựng một công cụ như vậy trong Node.js với GroupDocs.Metadata, qua bốn bước: chọn thuộc tính theo thẻ, chọn chúng theo tên, xóa mọi thứ khi việc chọn lọc không còn hiệu quả, và xác minh những gì còn lại. Mỗi bước chỉ vài dòng, và script hoàn chỉnh dưới một trăm dòng.

Tại sao việc làm sạch Metadata lại quan trọng

Dữ liệu tích lũy mà không có ai chọn lựa. Word ghi AuthorLastSavedBy từ tài khoản hệ điều hành mỗi khi lưu, giữ một bộ đếm phiên bản, theo dõi TotalEditingTime, và ghi LastPrinted. Các máy chủ tài liệu thêm đường dẫn quy trình làm việc, định danh người phê duyệt, và URI kiểu nội dung khi check‑in. Không có gì trong số này xuất hiện khi tài liệu được đọc hoặc in, vì vậy một người đọc lại sẽ không bao giờ bắt gặp chúng.

Mục đích thực hiện việc này bằng Node.js thay vì thủ công là script trả về số liệu: mỗi lần gọi xóa trả về số lượng thuộc tính đã bị xóa, và con số này có thể được ghi vào log, kiểm tra trong test, hoặc gắn vào bản ghi mà tài liệu thuộc về.

Có một lý do thứ hai, ít rõ ràng cho tới khi một công việc batch đang chạy. Việc dọn dẹp thủ công là quyết định được đưa ra một lần cho mỗi tệp bởi người đang xử lý, vì vậy hai người làm sạch cùng một loại tài liệu có thể cho ra kết quả khác nhau. Một script cố định quy tắc ở một nơi: cùng bốn thẻ, cùng danh sách chuỗi con, áp dụng đồng nhất dù hàng đợi có ba tệp hay ba nghìn tệp.

Yêu cầu trước

Gói này là Node.js thông qua Java, vì vậy máy cần có môi trường chạy Java cùng với Node.

Cài đặt

npm install @groupdocs/groupdocs.metadata

Dự án mẫu khóa phiên bản 26.7 và thêm mục overrides đặt nan thành ^2.22.0, giúp việc biên dịch native binding trên các phiên bản Node hiện tại. Nếu không có tệp giấy phép, thư viện chạy ở chế độ đánh giá, đủ để thực hiện mọi bước trong hướng dẫn này.

Bước 1 – Chọn thuộc tính theo ý nghĩa của chúng

Tên thuộc tính khác nhau giữa các định dạng và gói, vì vậy quy tắc đầu tiên khớp dựa trên thẻ. ContainsTagSpecification nhận một thẻ và khớp bất kỳ thuộc tính nào mang thẻ đó; .or() hợp nhất các specification thành một.

const T = groupdocs.Tags;
const spec = new groupdocs.ContainsTagSpecification(T.getPerson().getCreator())
  .or(new groupdocs.ContainsTagSpecification(T.getPerson().getEditor()))
  .or(new groupdocs.ContainsTagSpecification(T.getPerson().getManager()))
  .or(new groupdocs.ContainsTagSpecification(T.getCorporate().getCompany()));
const affected = metadata.removeProperties(spec);
metadata.save(outputPath);

Các điểm chính:

  • Bốn thẻ bao phủ nhóm nhận dạng: người tạo, người chỉnh sửa, người quản lý, và trường công ty doanh nghiệp.
  • Title, Subject và Keywords không bị chạm, vì vậy chỉ mục hồ sơ dựa trên chúng vẫn hoạt động.
  • removeProperties trả về số lượng bị ảnh hưởng thay vì một giá trị boolean.

Bao bọc toàn bộ trong try/finally với metadata.close() trong khối finally. Binding giữ tệp mở cho đến khi đóng, và một vòng lặp không có nó sẽ hết handle.

Bước 2 – Chọn thuộc tính theo tên

Các chuỗi bình luận, bộ đếm phiên bản và trường máy chủ không có thẻ. Đối với chúng, WithNameSpecification(needle, false) khớp bất kỳ thuộc tính nào có tên chứa needle, và một builder bốn dòng nối một specification cho mỗi chuỗi con:

let spec = null;
for (const needle of needles) {
  const s = new groupdocs.WithNameSpecification(needle, false /* fullMatch */);
  spec = spec ? spec.or(s) : s;
}
return spec;

Ba lượt chạy lại builder này với các danh sách khác nhau. Đầu tiên là các bình luận:

const affected = metadata.removeProperties(
  nameContainsSpec(['Comment', 'Reviewer', 'Reviewed']));
metadata.save(outputPath);

Tiếp theo là dòng thời gian chỉnh sửa, nhóm thường bị quên và là nhóm mô tả cách tài liệu được tạo ra:

const affected = metadata.removeProperties(nameContainsSpec([
  'Revision', 'TrackedChange', 'LastPrinted', 'TotalEditingTime', 'EditTime',
]));
metadata.save(outputPath);

Lượt chạy cho SharePoint là cùng một lời gọi với Server, Workflow, Approver, ContentType, và Template. Việc khớp chuỗi con là có chủ đích: nó bắt CommentsCount cùng với Comment mà không cần duy trì danh sách tên chính xác cho mỗi định dạng.

Bước 3 – Xóa mọi thứ khi việc chọn lọc không còn hiệu quả

Đối với bản sao sẽ rời khỏi tổ chức, một lời gọi thay thế ba lượt chạy trước:

const affected = metadata.sanitize();
metadata.save(outputPath);

sanitize() xóa mọi gói metadata mà thư viện phát hiện, bao gồm các phần OOXML tùy chỉnh, và số lượng thường vượt quá tổng của các lượt chạy mục tiêu. Nó cũng xóa Title và Subject, vì vậy nên dùng ở ranh giới thay vì trong vòng lặp kiểm tra.

Bước 4 – Xác minh, vì một lỗi im lặng trông giống như thành công

Quét lại sử dụng cùng các specification qua findProperties, chỉ đọc mà không ghi. Kết quả là một collection của Java, nên được duyệt bằng chỉ mục:

const props = metadata.findProperties(tagSpec.or(nameSpec));
for (let i = 0; i < props.getCount(); i++) {
  const p = props.get_Item(i);
  const val = p.getValue && p.getValue();
  const value = val ? String(val.getRawValue ? val.getRawValue() : val) : '';
  if (!value || value === '0' || value === '0.0') continue;
  leaks.push(`${p.getName()}=${value}`);
}

Bộ lọc “rỗng và bằng 0” có lý do tồn tại. Tôi đã thêm nó sau một lần chạy thất bại vì bộ đếm phiên bản đã được xóa thành 0, và quét đã báo cáo chính xác đó là một thuộc tính còn tồn tại.

Ví dụ Hoạt động Đầy đủ

Kho lưu trữ kết nối sáu hàm vào index.js, áp dụng giấy phép, chạy mỗi lượt qua resources/pii-sample.docx, xác nhận rằng mọi tệp đầu ra tồn tại, và kết thúc bằng việc xác nhận danh sách rò rỉ rỗng. Một assertion thất bại sẽ thoát với mã không bằng 0, vì vậy toàn bộ quá trình hoạt động như một kiểm tra trong CI thay vì một bản demo để đọc.

Một chi tiết đáng sao chép vào phiên bản của bạn: mỗi lượt đọc cùng một tệp nguồn và ghi ra một tệp đầu ra riêng, thay vì nối một tệp đã làm sạch vào lượt tiếp theo. Điều này giữ cho số lượng bị ảnh hưởng độc lập, vì vậy một dòng log cho lượt bình luận báo cáo những gì quy tắc bình luận tìm thấy chứ không phải những gì còn lại sau khi quy tắc nhận dạng đã chạy.

Khi nào nên chạy một lượt mục tiêu thay vì sanitize()?

Bất cứ khi nào tài liệu vẫn đang được sử dụng. Các tệp lưu thông giữa các reviewer dựa vào Title, Subject và Keywords để tìm kiếm và phân loại, và sanitize() sẽ xóa cả ba cùng với dữ liệu cá nhân. Hãy chạy các lượt nhận dạng và bình luận trong quá trình cộng tác, giữ các trường mô tả nguyên vẹn, và để việc xóa toàn bộ cho bản sao sẽ thực sự rời khỏi.

Ứng dụng Thực tế

Trình xử lý tải lên

Một route Express làm sạch tệp đính kèm trước khi ghi vào lưu trữ, ghi lại số lượng bị ảnh hưởng trên vé, và từ chối tải lên khi danh sách rò rỉ không rỗng.

Công việc xuất khẩu hàng đêm

Một worker duyệt thư mục xuất khẩu, áp dụng các lượt nhận dạng và máy chủ, và thất bại công việc thay vì ghi cảnh báo khi tài liệu vẫn còn báo cáo PII tồn tại.

Cổng kiểm duyệt trước khi công bố

Một bước build làm sạch các tệp đính kèm tài liệu trước khi phát hành, sử dụng sanitize() vì không có gì trong các tệp này cần giữ metadata.

Các Thực hành Tốt và Mẹo

  • Luôn ghi vào một đường dẫn mới để bản gốc còn lại cho việc giải quyết tranh chấp.
  • Đóng đối tượng metadata trong khối finally, đặc biệt trong các vòng lặp.
  • Hợp nhất các specification bằng .or() trong các công việc batch; một lần mở và một lần lưu nhanh hơn bốn lần.
  • Ghi lại số lượng bị ảnh hưởng cho mỗi lượt, kể cả giá trị 0, để một định dạng không được nhận diện có thể được phát hiện.

Khắc phục Các Vấn đề Thường gặp

Số lượng bị ảnh hưởng bằng 0 trên một tài liệu bạn biết là bẩn
Kiểm tra định dạng đầu vào có được nhận diện không trước khi kết luận tệp đã sạch; một tệp không đọc được và một tệp sạch đều cho cùng một số 0.

Kiểm tra rò rỉ báo cáo các thuộc tính bạn vừa mới xóa
Chỉ ra đường dẫn đầu ra đã lưu, không phải đường dẫn đầu vào. Quét sẽ đọc tệp mà nó nhận được.

Bong bóng bình luận vẫn hiển thị trong Word
Văn bản bình luận nằm trong thân tài liệu, không phải trong gói metadata. GroupDocs.Metadata xóa các thuộc tính liên quan đến bình luận; việc loại bỏ chính các bong bóng cần một thư viện chỉnh sửa nội dung như Aspose.Words.

Kết luận

Bốn bước, sáu hàm, một script báo cáo những gì nó đã làm. Các specification dựa trên thẻ xử lý nhóm nhận dạng qua các định dạng, các specification dựa trên tên bao phủ những nhóm thẻ không phân loại, sanitize() xử lý ranh giới, và quét rò rỉ biến toàn bộ quá trình thành một kiểm tra. Sao chép kho lưu trữ, chạy nó trên một tài liệu đã trải qua vòng duyệt thực tế, và xem các số lượng trước khi quyết định những lượt nào cần cho pipeline của bạn.

Tài nguyên Bổ sung