Нечитаемый код Excel 2010 после добавления гиперссылки Shape - PullRequest
0 голосов
/ 15 января 2019

У меня есть функция создания отчетов Excel в моем приложении Java.

Мне наконец-то удалось добавить к изображению гиперссылку без ошибок с помощью следующего кода.

buildHyperLinksMenu является основной функцией, которая устанавливает гиперссылку

createHyperLinkWithUri - это подфункция, которая создает гиперссылку Uri

public void buildHyperLinksMenu(String linkName, XSSFSheet sheet, String tabLinked, String referencedCell) {
    List<XSSFShape> shapes = sheet.getDrawingPatriarch().getShapes();
    Iterator<XSSFShape> elementsIterator = shapes.iterator();

    while (elementsIterator.hasNext()) {

        XSSFShape shape = elementsIterator.next();
        if (shape instanceof XSSFPicture) {
            CTPicture ctPicture = ((XSSFPicture) shape).getCTPicture();
            CTPictureNonVisual ctpicturenonvisual = ctPicture.getNvPicPr();
            CTNonVisualDrawingProps ctnonvisualdrawingprops = ctpicturenonvisual.getCNvPr();
            String finalname = ctnonvisualdrawingprops.getName();
            //HomeLink is the name of the picture assigned in the sheet to 
            //the image when uploading the Excel template
            if (finalname.equals("HomeLink")) {
                CTHyperlink link = createHyperLinkWithUri(linkName, sheet, tabLinked, referencedCell);
                ((XSSFPicture) shape).getCTPicture().getNvPicPr().getCNvPr().setHlinkClick(link);
            }
        }
    }
}

private CTHyperlink createHyperLinkWithUri(String linkName, XSSFSheet sheet, String tabLinked, String referencedCell) {
    CTHyperlink link = CTHyperlink.Factory.newInstance();
    try {
        String hyperlinkAddress = sheet.getPackagePart().getPartName() + "/#'" + tabLinked + "'!" + referencedCell + "";
        URI uri = new URI(null, null, hyperlinkAddress, null, null);
        sheet.getDrawingPatriarch().getPackagePart().addRelationship(uri, TargetMode.INTERNAL, XSSFRelation.SHEET_HYPERLINKS.getRelation());

        String relationshipId = null;
        PackageRelationshipCollection prc = sheet.getDrawingPatriarch().getPackagePart().getRelationships();
        for (PackageRelationship pr : prc) {
            URI targetURI = pr.getTargetURI();
            String target = targetURI.getPath();
            if (target.equals(hyperlinkAddress)) {
                relationshipId = pr.getId();
                break;
            }
        }

        CTHyperlink hyperlink = CTHyperlink.Factory.newInstance();
        // Set ID of hyperlink to be the same as Relationship ID
        hyperlink.setId(relationshipId);
        return hyperlink;
    } catch (URISyntaxException | InvalidFormatException e) {
        return link;
    }
}

Теперь проблема в том, что после генерации Excel (при открытии) выдаст сообщение «нечитаемый контент» и гиперссылка не будет добавлена.

Я хотел бы понять, если это проблема фрагмента кода, который я разместил, который мне не хватает, или что-то более раздражающее, например, версии библиотек и т. Д.

Я подтверждаю, что if (finalname.equals("HomeLink")) выполняется один и только один раз.

Вот простая функция, вызываемая для записи файла в вывод:

protected byte[] workbookToByteArray(XSSFWorkbook workbook) {
    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
        workbook.write(byteArrayOutputStream);

        return byteArrayOutputStream.toByteArray();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

Спасибо

Davide

UDPATE

Я сгенерировал документ Excel с функциональностью добавления гиперссылки и без нее (в основном код выше).

Поврежденный Excel говорит, что поврежден файл xl \ drawing \ drawing4.xml. Поэтому я взял два экземпляра, разархивировал их и сравнил XML-файлы. Единственные различия между этими двумя:

Правильный файл

<a:blip xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:embed="rId2">

против

Неверный файл

<a:blip r:embed="rId2">

Эта разница происходит много раз таким же образом. Много других

UDPATE

Похоже, что строка, которая создает проблему, при добавлении отношения к пакету

    sheet.getDrawingPatriarch().getPackagePart().addRelationship(uri, TargetMode.INTERNAL, XSSFRelation.SHEET_HYPERLINKS.getRelation());

КОД РЕШЕНИЯ

public void buildHyperLinksMenu(String linkName, XSSFSheet sheet, String tabLinked, String referencedCell) {
    List<XSSFShape> shapes = sheet.getDrawingPatriarch().getShapes();
    Iterator<XSSFShape> elementsIterator = shapes.iterator();

while (elementsIterator.hasNext()) {

    XSSFShape shape = elementsIterator.next();
    if (shape instanceof XSSFPicture) {
        CTPicture ctPicture = ((XSSFPicture) shape).getCTPicture();
        CTPictureNonVisual ctpicturenonvisual = ctPicture.getNvPicPr();
        CTNonVisualDrawingProps ctnonvisualdrawingprops = ctpicturenonvisual.getCNvPr();                 
        String finalname = ctnonvisualdrawingprops.getName();
        if (finalname.equals("HomeLink")) {
            CTHyperlink link = createHyperLinkWithUri(linkName, sheet, tabLinked, referencedCell);
            ((XSSFPicture) shape).getCTPicture().getNvPicPr().getCNvPr().setHlinkClick(link);


        }
    }
}

}

private CTHyperlink createHyperLinkWithUri(String linkName, XSSFSheet sheet, String tabLinked, String referencedCell) {
    CTHyperlink link = CTHyperlink.Factory.newInstance();
    try {
        CTHyperlink hyperlink = CTHyperlink.Factory.newInstance();
        String hyperlinkAddress = "#'" + tabLinked + "'!" + referencedCell + "";
        sheet.getDrawingPatriarch().getPackagePart().addExternalRelationship(hyperlinkAddress, PackageRelationshipTypes.HYPERLINK_PART);

        String relationshipId = null;
        PackageRelationshipCollection prc = sheet.getDrawingPatriarch().getPackagePart().getRelationships();
        for (PackageRelationship pr : prc) {
            String targetURI = pr.getTargetURI().toString();
            if (targetURI.equals(hyperlinkAddress)) {
                relationshipId = pr.getId();
                break;
            }
        }

        // Set ID of hyperlink to be the same as Relationship ID
        hyperlink.setId(relationshipId);
        return hyperlink;
    } catch (InvalidFormatException e) {
        return link;
    }
}
...