Creación, edición y análisis de DOCX
Un archivo .docx es un archivo ZIP que contiene archivos XML. Elige tu enfoque según la tarea:
| Tarea | Enfoque |
|---|---|
| Crear un documento nuevo | Escribir un script con docx (npm) — ver errores comunes abajo |
| Editar un documento existente | unzip → editar word/document.xml → zip (docx-js no puede abrir archivos existentes) |
| Leer contenido | pandoc -t markdown file.docx |
Las rutas de los scripts a continuación son relativas al directorio de esta habilidad.
Creación con docx-js — errores comunes
docx ya está preinstalado — no ejecutes npm install primero; escribe el script y usa require('docx') directamente. Solo si ese require falla: npm install docx. El modelo conoce la API; estos son los puntos problemáticos:
- El tamaño de página predeterminado es A4. Para Carta EE. UU. configura
page: { size: { width: 12240, height: 15840 } }(DXA; 1440 = 1″). - Horizontal: pasa las dimensiones verticales y
orientation: PageOrientation.LANDSCAPE— docx-js intercambia ancho/alto internamente. - Las tablas necesitan anchos duales: configura
columnWidthsen la tabla Ywidthen cada celda, ambos enWidthType.DXA(PORCENTAJE falla en Google Docs). Los anchos de las columnas deben sumar el ancho de la tabla. - Sombreado de tabla: usa
ShadingType.CLEAR, nuncaSOLID(se renderiza negro). - Listas: nunca insertes
•literalmente; usa una configuración denumberingconLevelFormat.BULLET. ImageRunrequieretype:("png","jpg", …).PageBreakdebe estar dentro de unParagraph.- Nunca uses
\n— usa elementosParagraphseparados. - TOC: los encabezados deben usar los
HeadingLevel.*integrados; los estilos de encabezado personalizados necesitanoutlineLevelconfigurado o no aparecerán. - No uses una tabla como regla horizontal — usa mejor un borde inferior de párrafo.
- Línea de puntos / alineado a la derecha en la misma línea: usa
PositionalTab(alignment: PositionalTabAlignment.RIGHT,leader: PositionalTabLeader.DOT) dentro de unTextRun, no puntos literales ni rellenos con espacios.
Verificar la salida
Después de escribir un .docx, renderízalo y míralo:
python scripts/office/soffice.py --headless --convert-to pdf output.docx
pdftoppm -jpeg -r 100 output.pdf page
ls page-*.jpg # luego Leer las imágenes
pdftoppm rellena con ceros los números de página hasta el ancho del recuento de páginas (page-01.jpg…page-12.jpg).
Editar documentos existentes
Los archivos .doc heredados deben convertirse primero: python scripts/office/soffice.py --headless --convert-to docx file.doc.
unzip -q doc.docx -d unpacked/
find unpacked -type l -delete # eliminar entradas de enlace simbólico — el docx de terceros no es fiable
python scripts/merge_runs.py unpacked/ # fusiona fragmentos de texto para que el texto sea buscable
# editar unpacked/word/document.xml in situ — NO reformatear ni embellecer
(cd unpacked && rm -f ../out.docx && zip -Xr ../out.docx .)
python scripts/office/validate.py out.docx --original doc.docx # comprobaciones XSD; --auto-repair corrige problemas comunes
# ¿cambios controlados? añade --author "<el nombre bajo el que hiciste cambios>" para verificar que cada edición está registrada
Word divide el texto en muchas ejecuciones <w:r> (identificadores de revisión, marcadores de corrección ortográfica), por lo que una frase que ves en el documento a menudo no existe como cadena contigua en el XML. merge_runs.py fusiona ejecuciones adyacentes con el mismo formato en word/document.xml sin cambiar el contenido ni el renderizado; también acepta un .docx directamente (python scripts/merge_runs.py doc.docx -o merged.docx).
Cambios controlados: al hacer marcas de cambio, valida con --author "<el nombre bajo el que hiciste cambios>" (necesita --original) — informa de cualquier texto que hayas cambiado sin un <w:ins>/<w:del> alrededor, lo cual es fácil de hacer accidentalmente e invisible en la vista aceptada. Envuelve las ejecuciones en <w:ins>/<w:del> con atributos w:id, w:author, w:date. Dentro de <w:del>, el elemento de texto es <w:delText>, no <w:t>. Una marca de párrafo eliminada (<w:pPr><w:rPr><w:del w:id=".." w:author=".." w:date="../></w:rPr></w:pPr>) significa "fusiona este párrafo con el siguiente" — por lo tanto, eliminar un párrafo por completo es eso más un <w:del> alrededor de cada ejecución. El <w:del/> debe ir antes de los otros hijos de rPr; su orden está impuesto por el esquema.
Para producir una copia limpia con todos los cambios controlados aceptados: python scripts/accept_changes.py in.docx out.docx.
Aceptar una marca de párrafo eliminada debería unir ese párrafo al siguiente, por lo que un párrafo cuyas ejecuciones están todas eliminadas desaparece. Word hace esto; accept_changes.py y pandoc --track-changes=accept no siempre lo hacen. Ambos fallan de la misma manera: eliminan el texto eliminado pero dejan el párrafo vacío, que se lee como una viñeta vacía perdida cuando estaba auto numerada:
pandoc --track-changes=acceptnunca une los párrafos.accept_changes.py(LibreOffice) los une correctamente, excepto cuando el párrafo eliminado va seguido de un párrafo espaciador vacío.
Una viñeta vacía en cualquiera de las vistas es un artefacto de esa vista, no un defecto en el documento. Verifica las eliminaciones de párrafos en el XML.
Comentarios
Los comentarios requieren seis archivos vinculados entre sí. Usa el ayudante — modo directorio cuando también vayas a editar document.xml (ahorra un ciclo de descompresión/recompresión), modo .docx directo en caso contrario:
# Contra un directorio ya descomprimido (preferido al colocar también marcadores)
python scripts/comment.py unpacked/ "El límite de tarifas y gastos es demasiado bajo"
python scripts/comment.py unpacked/ "De acuerdo" --parent 0
# Contra un .docx directamente
python scripts/comment.py contract.docx "Este límite es demasiado bajo" -o annotated.docx
El script escribe comments.xml, commentsExtended.xml, commentsIds.xml, commentsExtensible.xml, las relaciones y las anulaciones de tipo de contenido. Los ID de comentario se asignan automáticamente. Luego imprime el fragmento <w:commentRangeStart>/<w:commentRangeEnd>/<w:commentReference> para añadir a word/document.xml para que el comentario se ancle a un texto específico — hasta que coloques esos marcadores, el comentario existe pero no es visible.
Dependencias
docx (npm, preinstalado — instalar solo si falla require('docx')) · pandoc · LibreOffice (soffice) · pdftoppm (Poppler)