Невозможно нарисовать SVG в PDF с помощью Apache FOP — обнаружен неизвестный объект форматирования «{}svg» (дочерний элемент fo:instream-foreign-object}

Я создал следующий код для простого флажка в таблице, используя XSL-FO:

Java-код

Element svg = document.createElement("svg");
svg.setAttribute("width", "12pt");
svg.setAttribute("height", "12pt");
svg.setAttribute("viewBox", "0 0 24 24");

Element rect = document.createElement("rect");
rect.setAttribute("x", "2");
rect.setAttribute("y", "2");
rect.setAttribute("width", "20");
rect.setAttribute("height", "20");
rect.setAttribute("fill", "none");
rect.setAttribute("stroke", "black");
svg.appendChild(rect);
<fo:table-cell border = "solid 1px black" font-family = "Arial" font-size = "12pt" padding = "2pt">
 <fo:block>
  <fo:inline>Checkbox: </fo:inline>
  <fo:inline>
   <fo:instream-foreign-object>
    <svg height = "12pt" viewBox = "0 0 24 24" width = "12pt">
     <rect fill = "none" height = "20" stroke = "black" width = "20" x = "2" y = "2"/>
    </svg>
   </fo:instream-foreign-object>
  </fo:inline>
 </fo:block>
</fo:table-cell>

Однако когда я пытаюсь преобразовать его в PDF, я получаю следующее предупреждение: Unknown formatting object "{}svg" encountered (a child of fo:instream-foreign-object}

Что может быть причиной этой ошибки?

Я попробовал добавить свойства SVG в конфигурацию FOP и использовать тег fo:svg, но это все равно не работает должным образом.

Вы уверены, что вам не следует использовать createElementNS вместо createElement?

Robert Longson 02.09.2024 15:17

@RobertLongson попробую, спасибо

KnightDanila 02.09.2024 15:25

Вы объявили пространство имен SVG в документе FO? Из фрагмента видно, что пространство имен SVG является основным пространством имен, но если это указано как svg:xmlns = "...", все элементы в пространстве имен SVG должны иметь svg:... перед именем элемента. Или создано с помощью createElementNS, как упоминает @RobertLongson.

chrwahl 02.09.2024 22:11

Спасибо, @chrwahl, за идею с xmlns. Что касается svg:..., то у них не должно быть svg:..., это лишнее. Я исправил это, просто добавив xmlns = "http://www.w3.org/2000/svg".

KnightDanila 04.09.2024 11:28
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

FOP должен знать тип XML, который вы ему передаете. В этом случае задействованы два пространства имен XML; Объекты форматирования http://www.w3.org/1999/XSL/Format и SVG http://www.w3.org/2000/svg.

Существуют разные способы объявления пространства имен. И вы можете увидеть их в этом примере PDF. В следующем примере пространство имен SVG просто объявляется в элементе svg, а затем FOP знает, что все дочерние элементы принадлежат к одному и тому же пространству имен (если не объявлено другое пространство имен).

<?xml version = "1.0" encoding = "UTF-8"?>
<root xmlns = "http://www.w3.org/1999/XSL/Format">
  <layout-master-set>
    <simple-page-master margin = "10mm" page-width = "210mm" page-height = "297mm" master-name = "simple">
      <region-body region-name = "simple-body" margin-bottom = "20mm" margin-top = "20mm" />
    </simple-page-master>
  </layout-master-set>
  <page-sequence master-reference = "simple">
    <flow flow-name = "simple-body">
      <block>Hello World!</block>
      <block>
        <instream-foreign-object>
          <svg xmlns = "http://www.w3.org/2000/svg" height = "12pt" viewBox = "0 0 24 24" width = "12pt">
            <rect fill = "none" height = "20" stroke = "black" width = "20" x = "2" y = "2"/>
          </svg>
        </instream-foreign-object>
      </block>
    </flow>
  </page-sequence>
</root>

В Java, вероятно, будет нормально, если вы просто используете createElementNS с пространством имен SVG, и Java узнает, как объявить пространство имен SVG в XML-документе.

В качестве примера XSL-FO вы добавляете в смесь пространство имен XSL http://www.w3.org/1999/XSL/Transform, позволяя либо XSL, либо пространству имен FO быть основным. В этом случае я думаю, что имеет смысл использовать FO в качестве основного, поскольку результатом преобразования XSL является документ FO (со встроенным в него некоторым количеством SVG).

<?xml version = "1.0"?>
<xsl:stylesheet version = "1.0"
  xmlns = "http://www.w3.org/1999/XSL/Format"
  xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
  xmlns:svg = "http://www.w3.org/2000/svg">

  <xsl:template match = "/">
    <root>
      <layout-master-set>
        <simple-page-master margin = "10mm" page-width = "210mm" page-height = "297mm" master-name = "simple">
          <region-body region-name = "simple-body" margin-bottom = "20mm" margin-top = "20mm" />
        </simple-page-master>
      </layout-master-set>
      <page-sequence master-reference = "simple">
        <flow flow-name = "simple-body">
          <block>Hello World!</block>
          <block>
            <instream-foreign-object>
              <svg:svg height = "12pt" viewBox = "0 0 24 24" width = "12pt">
                <svg:rect fill = "none" height = "20" stroke = "black" width = "20" x = "2" y = "2"/>
              </svg:svg>
          </instream-foreign-object>
        </block>
      </flow>
    </page-sequence>
  </root>
</xsl:template>

</xsl:stylesheet>

Спасибо @chrwahl

Исправили это, просто добавив xmlns="http://www.w3.org/2000/svg". Этого было достаточно.

Element svg = document.createElement("svg");
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svg.setAttribute("width", "12pt");
svg.setAttribute("height", "12pt");
svg.setAttribute("viewBox", "0 0 24 24");

Другие вопросы по теме