💡 Contoh lengkap yang berfungsi tersedia di GitHub:
office-metadata-pii-cleanup-nodejs
Pendahuluan
Sebuah endpoint unggahan menerima file DOCX dari seorang staf dan menyimpannya pada tiket pelanggan. Teksnya baik‑baik saja. Properti‑propertinya tidak: nama orang yang menulisnya, rekan yang terakhir menyimpannya, manajer departemen dari templat korporat, dan, karena file tersebut berasal dari SharePoint, approver yang menandatanganinya.
Pembersih metadata adalah skrip kecil yang menghapus properti‑properti tersebut sebelum file disimpan dan kemudian memeriksa hasilnya. Tutorial ini membangun pembersih tersebut di Node.js dengan GroupDocs.Metadata, dalam empat langkah: memilih properti berdasarkan tag, memilihnya berdasarkan nama, menghapus semuanya ketika selektivitas tidak lagi membantu, dan memverifikasi apa yang tersisa. Setiap langkah hanya beberapa baris, dan skrip selesai kurang dari seratus baris.
Mengapa Sanitasi Metadata Penting
Data terakumulasi tanpa ada yang memilihnya. Word menulis Author dan LastSavedBy dari akun sistem operasi pada setiap penyimpanan, menyimpan penghitung revisi, melacak TotalEditingTime, dan mencatat LastPrinted. Server dokumen menambahkan jalur alur kerja, pengidentifikasi approver, dan URI tipe konten pada saat check‑in. Semua ini tidak muncul ketika dokumen dibaca atau dicetak, sehingga proses proofreading tidak pernah menangkapnya.
Inti melakukan ini di Node.js alih‑alih secara manual adalah bahwa skrip mengembalikan angka: setiap pemanggilan penghapusan melaporkan berapa banyak properti yang dihapus, dan jumlah tersebut dapat dituliskan ke log, dijadikan asersi dalam tes, atau dilampirkan pada catatan dokumen.
Ada alasan kedua, yang kurang jelas sampai sebuah pekerjaan batch dijalankan. Pembersihan manual adalah keputusan yang dibuat sekali per file oleh siapa pun yang menanganinya, sehingga dua orang yang membersihkan jenis dokumen yang sama menghasilkan hasil yang berbeda. Skrip memperbaiki aturan di satu tempat: empat tag yang sama, daftar substring yang sama, diterapkan secara identik apakah antrean berisi tiga file atau tiga ribu file.
Prasyarat
Paket ini adalah Node.js via Java, jadi mesin harus memiliki runtime Java bersamaan dengan Node.
Instalasi
npm install @groupdocs/groupdocs.metadata
Proyek contoh mengunci versi 26.7 dan menambahkan entri overrides yang mengatur nan ke ^2.22.0, yang menjaga agar binding native dapat dibangun pada rilis Node saat ini. Tanpa file lisensi, perpustakaan berjalan dalam mode evaluasi, yang cukup untuk mengikuti setiap langkah di sini.
Langkah 1 - Pilih properti berdasarkan arti mereka
Nama properti berbeda antar format dan paket, jadi aturan pertama mencocokkan berdasarkan tag. ContainsTagSpecification mengambil sebuah tag dan mencocokkan setiap properti yang memuatnya; .or() menggabungkan spesifikasi menjadi satu.
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);
Poin penting:
- Empat tag mencakup grup identitas: creator, editor, manager, dan bidang perusahaan korporat.
- Title, Subject, dan Keywords tidak tersentuh, sehingga indeks catatan yang mengindeksnya tetap berfungsi.
removePropertiesmengembalikan jumlah yang terpengaruh, bukan nilai boolean.
Bungkus seluruh proses dalam try/finally dengan metadata.close() di dalam finally. Binding menahan file tetap terbuka sampai saat itu, dan loop tanpa penutupan akan kehabisan handle.
Langkah 2 - Pilih properti berdasarkan nama
Thread komentar, penghitung revisi, dan bidang server tidak membawa tag. Untuk itu, WithNameSpecification(needle, false) mencocokkan setiap properti yang namanya mengandung needle, dan pembangun empat baris menambahkan satu per substring:
let spec = null;
for (const needle of needles) {
const s = new groupdocs.WithNameSpecification(needle, false /* fullMatch */);
spec = spec ? spec.or(s) : s;
}
return spec;
Tiga kali iterasi menggunakan pembangun tersebut dengan daftar yang berbeda. Komentar diproses pertama:
const affected = metadata.removeProperties(
nameContainsSpec(['Comment', 'Reviewer', 'Reviewed']));
metadata.save(outputPath);
Linimasa penyuntingan adalah grup yang cenderung terlupakan, dan merupakan grup yang menjelaskan bagaimana dokumen diproduksi:
const affected = metadata.removeProperties(nameContainsSpec([
'Revision', 'TrackedChange', 'LastPrinted', 'TotalEditingTime', 'EditTime',
]));
metadata.save(outputPath);
Pass SharePoint menggunakan pemanggilan yang sama dengan Server, Workflow, Approver, ContentType, dan Template. Pencocokan substring sengaja dipakai: ia menangkap CommentsCount bersamaan dengan Comment tanpa harus memelihara daftar nama tepat per format.
Langkah 3 - Hapus semuanya ketika selektivitas tidak membantu
Untuk salinan yang akan meninggalkan organisasi, satu pemanggilan menggantikan empat pass sebelumnya:
const affected = metadata.sanitize();
metadata.save(outputPath);
sanitize() menghapus setiap paket metadata yang terdeteksi perpustakaan, termasuk bagian OOXML khusus, dan jumlahnya biasanya melebihi total dari pass yang ditargetkan. Ia juga mengambil Title dan Subject, itulah mengapa fungsi ini diletakkan di batas akhir, bukan dalam loop review.
Langkah 4 - Verifikasi, karena kegagalan diam tampak seperti keberhasilan
Pemindaian kembali menggunakan spesifikasi yang sama melalui findProperties, yang membaca tanpa menulis. Hasilnya adalah koleksi Java, sehingga diakses lewat indeks:
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}`);
}
Filter kosong‑dan‑nol memperoleh tempatnya. Saya menambahkannya setelah satu kali run gagal karena penghitung revisi yang telah dibersihkan menjadi 0, yang dipindai dengan setia sebagai properti yang masih ada.
Contoh Kerja Lengkap
Repositori menghubungkan enam fungsi ke dalam index.js, yang menerapkan lisensi, menjalankan setiap pass terhadap resources/pii-sample.docx, memastikan setiap file output ada, dan mengakhiri dengan memastikan daftar kebocoran kosong. Asersi yang gagal keluar dengan kode non‑zero, sehingga seluruh proses berfungsi sebagai pemeriksaan di CI alih‑alih demo yang hanya dibaca.
Satu detail layak disalin ke versi Anda sendiri: setiap pass membaca file sumber yang sama dan menulis output terpisah, bukan menumpuk satu file yang sudah dibersihkan ke pass berikutnya. Ini membuat jumlah yang terpengaruh tetap independen, sehingga baris log untuk pass komentar melaporkan apa yang ditemukan aturan komentar, bukan apa yang tersisa setelah aturan identitas dijalankan.
Kapan Saya Harus Menjalankan Pass Terarah Alih‑alih sanitize()?
Setiap kali dokumen masih digunakan. File yang beredar di antara reviewer mengandalkan Title, Subject, dan Keywords untuk pencarian dan klasifikasi, dan sanitize() menghapus ketiganya bersama data pribadi. Jalankan pass identitas dan komentar selama kolaborasi, pertahankan bidang deskriptif tetap utuh, dan simpan penghapusan total untuk salinan yang benar‑benar akan keluar.
Aplikasi Dunia Nyata
Penangani unggahan
Rute Express membersihkan lampiran sebelum menulisnya ke penyimpanan, mencatat jumlah yang terpengaruh pada tiket, dan menolak unggahan bila daftar kebocoran tidak kosong.
Pekerjaan ekspor malam
Worker menelusuri folder ekspor, menerapkan pass identitas dan server, dan gagal menjalankan pekerjaan alih‑alih mencatat peringatan bila dokumen masih melaporkan PII residual.
Gerbang pra‑publikasi
Langkah build membersihkan lampiran dokumentasi sebelum rilis, menggunakan sanitize() karena tidak ada metadata dalam file tersebut yang perlu dipertahankan.
Praktik Terbaik dan Tips
- Selalu tulis ke jalur baru sehingga file asli tetap ada untuk penyelesaian sengketa.
- Tutup objek metadata dalam blok
finally, terutama di dalam loop. - Gabungkan spesifikasi dengan
.or()dalam pekerjaan batch; satu pembukaan dan satu penyimpanan lebih efisien daripada empat. - Catat jumlah yang terpengaruh per pass, termasuk nol, sehingga format yang tidak dikenali terlihat.
Pemecahan Masalah Umum
Jumlah yang terpengaruh nol pada dokumen yang Anda tahu kotor
Periksa bahwa format input dikenali sebelum menyimpulkan file bersih; file yang tidak dapat dibaca dan file bersih menghasilkan nol yang sama.
Pemeriksaan kebocoran melaporkan properti yang baru saja Anda hapus
Arahkan ke jalur output yang sudah disimpan, bukan jalur input. Pemindaian membaca file yang diberikan kepadanya.
Balon komentar masih terlihat di Word
Teks komentar berada di badan dokumen, bukan di paket metadata. GroupDocs.Metadata menghapus properti terkait komentar; menghilangkan balon itu sendiri memerlukan perpustakaan pengedit konten seperti Aspose.Words.
Kesimpulan
Empat langkah, enam fungsi, satu skrip yang melaporkan apa yang dilakukannya. Spesifikasi tag menangani grup identitas lintas format, spesifikasi nama menutupi keluarga yang tidak diklasifikasikan tag, sanitize() menangani batas akhir, dan pemindaian kebocoran mengubah semuanya menjadi pemeriksaan. Kloning repositori, jalankan pada dokumen yang telah melewati putaran review nyata, dan perhatikan jumlahnya sebelum memutuskan pass mana yang dibutuhkan pipeline Anda.