Skip to content

Repository files navigation

EndNote Field Code Converter — Hardened 2.0.2

Plain-text citations and an existing reference list in a Microsoft Word .docx manuscript are converted into EndNote-compatible Word fields while preserving the document's visible text and formatting as far as the OOXML structure permits.

The hardened converter is the default entry point:

python endnote_docx.py -i manuscript.docx -o manuscript_EndNote.docx --strict

The original specialized converters remain in endnote-fieldcode-converter/scripts/ for compatibility, but new conversions should start with the root-level endnote_docx.py.

Why this build is different

The converter does not rewrite whole paragraphs. It isolates only the detected citation range, preserves the existing result text and run properties, and inserts compound Word fields containing:

  • ADDIN EN.CITE
  • nested ADDIN EN.CITE.DATA
  • Base64-encoded EndNote XML with the cited records
  • one ADDIN EN.REFLIST wrapper around the existing bibliography when the reference section can be wrapped safely

It also provides a deterministic fallback for documents that cannot be resolved automatically. An analysis report contains a manual_mapping_template; unresolved citations, missing references, or nonstandard citation spans can be explicitly mapped and then converted in --strict mode.

Installation

Python 3.9 or later is recommended.

python -m pip install -r requirements-hardened.txt

Only lxml is required by the hardened converter.

Safe workflow

1. Analyze first

python endnote_docx.py \
  -i manuscript.docx \
  --analyze \
  --strict \
  --report manuscript.endnote-analysis.json

In strict analysis mode, exit code 1 means that the report contains an unresolved or unsafe item. No output DOCX is written.

2. Convert when the report is clean

python endnote_docx.py \
  -i manuscript.docx \
  -o manuscript_EndNote.docx \
  --strict \
  --report manuscript.endnote-report.json

3. Supply external bibliographic metadata when needed

python endnote_docx.py \
  -i manuscript.docx \
  -o manuscript_EndNote.docx \
  --metadata library.ris \
  --metadata additional.bib \
  --strict

Supported metadata inputs are RIS, ENW/EndNote tagged text, BibTeX, JSON, and CSL-JSON.

4. Resolve ambiguous or nonstandard cases explicitly

Edit the manual_mapping_template in the analysis report, or save that object as a separate JSON file, and run:

python endnote_docx.py \
  -i manuscript.docx \
  -o manuscript_EndNote.docx \
  --mapping manuscript.endnote-mapping.json \
  --strict

See MANUAL_MAPPING_KO.md, manual-mapping.schema.json, and examples/manual-mapping.example.json.

Supported citation forms

Automatic detection covers common forms including:

  • [1], [1,2,5], [1–3,5]
  • (1), (1, 2)
  • full-width punctuation variants
  • true superscript numeric citations
  • (Smith, 2020; Jones, 2021)
  • Smith et al. (2020) and corresponding Korean narrative author-year patterns
  • EndNote temporary citations such as {Smith, 2020 #15}
  • citation text split across adjacent Word runs
  • citations in the main document, tables, headers, footers, footnotes, endnotes, comments, glossary parts, and text boxes when represented as WordprocessingML paragraphs

Existing EndNote fields are detected and not nested again. Text in deleted tracked-change markup or hidden text is not treated as an ordinary visible citation.

Reference handling

A reference section is detected under headings such as References, Reference, Bibliography, or 참고문헌. Explicit bracketed or dotted numbering is preferred. The parser extracts, where available:

  • authors
  • year
  • title
  • journal or book title
  • publisher
  • volume, issue, and pages
  • DOI
  • PMID
  • URL
  • original formatted reference text

External metadata is matched first by DOI or PMID, then conservatively by title and author/year. Ambiguous matches are reported rather than guessed.

Preservation and validation

Before a final DOCX is committed, the converter checks:

  • visible text equality before and after conversion
  • per-character run-property equality for visible result text
  • balanced Word field begin/separate/end markers
  • decodable w:fldData payloads and valid EndNote XML records
  • ZIP integrity and XML parseability
  • reopening and revalidating the staging DOCX
  • unchanged ZIP members retaining their original byte hashes
  • absence of unresolved items in strict mode

The output is written to a staging file first and then atomically moved into place. --in-place is available only explicitly and creates a .pre-endnote.bak backup after staging validation.

Command-line options

-i, --input PATH              input DOCX
-o, --output PATH             output DOCX; default: *_EndNote.docx
--report PATH                 JSON analysis/conversion report
--analyze                     analyze only; do not write a DOCX
--strict                      block output if any unresolved or unsafe item remains
--mapping PATH                manual mapping JSON or prior report
--ignore-mapping-hash         deliberately use a mapping made for another DOCX
--metadata PATH               RIS, ENW, BibTeX, JSON, or CSL-JSON; repeatable
--stories all|main            process all Word story parts or main document only
--citation-style MODE         auto|all|lancet|numeric|author-year|temporary
--bibliography wrap|keep|none wrap existing bibliography, retain it unfielded, or skip
--overwrite                   replace an existing output or backup
--in-place                    replace input after validation and create backup

Run python endnote_docx.py --help for the authoritative option list.

Repository layout

.
├── endnote_docx.py                         # hardened converter
├── requirements-hardened.txt
├── QUICKSTART_KO.md
├── MANUAL_MAPPING_KO.md
├── WORD_ENDNOTE_ACCEPTANCE_CHECKLIST_KO.md
├── BUILD_VERIFICATION.md
├── CHANGELOG_HARDENED.md
├── manual-mapping.schema.json
├── examples/
│   └── manual-mapping.example.json
├── tests/
│   └── test_hardened_converter.py
└── endnote-fieldcode-converter/            # original Skill and legacy utilities
    └── scripts/
        └── endnote_docx.py                  # compatibility launcher to root converter

Important boundary

The converter can always reach a deterministic outcome for an ordinary, readable, unsigned DOCX by either automatic mapping or explicit manual mapping. It intentionally does not claim that every document can be converted without review. Structurally corrupt, encrypted, or digitally signed packages are blocked; a working unsigned copy is required. Citations whose exact text range cannot be isolated safely are also blocked in strict mode rather than converted destructively.

Microsoft Word and the proprietary EndNote CWYW add-in are still required for the final application-level acceptance test, including opening the document, editing one citation, and running "Update Citations and Bibliography". Use WORD_ENDNOTE_ACCEPTANCE_CHECKLIST_KO.md for that test.

Tests

python -m unittest discover -s tests -v

A reproducible verification wrapper is also included:

python verify_hardened_build.py

License

MIT. See LICENSE.

Releases

Packages

Contributors

Languages