Санитарная обработка документа SVG с помощью элементов белого списка - PullRequest
7 голосов
/ 03 февраля 2011

Я хочу извлечь около 20 типов элементов из некоторых документов SVG, чтобы сформировать новый SVG.rect, circle, polygon, text, polyline, в основном набор визуальных частей находится в белом списке.JavaScript, комментарии, анимация и внешние ссылки должны быть отправлены.

На ум приходят три метода:

  1. Regex: Я полностью знаком с этим и, очевидно, предпочел бы не ходить туда.
  2. PHP DOM: Использовался один раз, может быть, год назад.
  3. XSLT: Я только сейчас посмотрел на меня.

Если XSLT является подходящим инструментом для работы, какая таблица стилей xsl: мне нужна?В противном случае, какой подход вы бы использовали?

Пример ввода:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" width="512" height="512" id="svg2">
<title>Mostly harmless</title>
  <metadata id="metadata7">Some metadata</metadata>

<script type="text/ecmascript">
<![CDATA[
alert('Hax!');
]]>
</script>
<style type="text/css">
<![CDATA[ svg{display:none} ]]>
</style>

  <defs id="defs4">
    <circle id="my_circle" cx="100" cy="50" r="40" fill="red"/> 
  </defs>

  <g id="layer1">
  <a xlink:href="www.hax.ru">
    <use xlink:href="#my_circle" x="20" y="20"/>
    <use xlink:href="#my_circle" x="100" y="50"/>
  </a>
  </g>
  <text>
    <tspan>It was the best of times</tspan>
    <tspan dx="-140" dy="15">It was the worst of times.</tspan>
  </text>
</svg>

Пример вывода.Отображает точно такое же изображение:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512">
  <defs>
    <circle id="my_circle" cx="100" cy="50" r="40" fill="red"/> 
  </defs>
  <g id="layer1">
    <use xlink:href="#my_circle" x="20" y="20"/>
    <use xlink:href="#my_circle" x="100" y="50"/>
  </g>
  <text>
    <tspan>It was the best of times</tspan>
    <tspan dx="-140" dy="15">It was the worst of times.</tspan>
  </text>
</svg>

Примерный список элементов хранителя: g, rect, circle, ellipse, line, polyline, polygon, path, text, tspan, tref, textpath, linearGradient+stop, radialGradient, defs, clippath, path.

Если не совсем SVG-крошечный, то, конечно, SVG lite.

Ответы [ 4 ]

4 голосов
/ 03 февраля 2011

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:s="http://www.w3.org/2000/svg"
 >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="*">
  <xsl:element name="{name()}" namespace="{namespace-uri()}">
   <xsl:copy-of select="namespace::xlink"/>

   <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:attribute name="{name()}"
                 namespace="{namespace-uri()}">
   <xsl:value-of select="."/>
  </xsl:attribute>
 </xsl:template>

 <xsl:template match="s:a">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match=
 "s:title|s:metadata|s:script|s:style|
  s:svg/@version|s:svg/@id"/>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:cc="http://creativecommons.org/ns#"
     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     xmlns:svg="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     xmlns="http://www.w3.org/2000/svg" version="1.1"
     width="512" height="512" id="svg2">
    <title>Mostly harmless</title>
    <metadata id="metadata7">Some metadata</metadata>
    <script type="text/ecmascript"><![CDATA[ alert('Hax!'); ]]></script>
    <style type="text/css"><![CDATA[ svg{display:none} ]]></style>
    <defs id="defs4">
        <circle id="my_circle" cx="100" cy="50" r="40" fill="red"/>
    </defs>
    <g id="layer1">
        <a xlink:href="www.hax.ru">
            <use xlink:href="#my_circle" x="20" y="20"/>
            <use xlink:href="#my_circle" x="100" y="50"/>
        </a>
    </g>
    <text>
        <tspan>It was the best of times</tspan>
        <tspan dx="-140" dy="15">It was the worst of times.</tspan>
    </text>
</svg>

дает желаемый, правильный результат :

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512">
   <defs id="defs4">
      <circle id="my_circle" cx="100" cy="50" r="40" fill="red"/>
   </defs>
   <g id="layer1">
      <use xlink:href="#my_circle" x="20" y="20"/>
      <use xlink:href="#my_circle" x="100" y="50"/>
   </g>
   <text>
      <tspan>It was the best of times</tspan>
      <tspan dx="-140" dy="15">It was the worst of times.</tspan>
   </text>
</svg>

Объяснение

  1. Два шаблона, имеющие комбинированный эффект, аналогичный правилу идентификации, соответствуют всем «узлам белого списка» и, по сути, копируют их (исключая только нежелательные узлы пространства имен).

  2. Шаблон без тела соответствует всем «черным спискам» узлов (элементы и некоторые атрибуты). Они фактически удалены.

  3. Должны быть шаблоны, которые соответствуют определенным узлам «серого списка» (шаблон, соответствующий s:a в нашем случае). «Серый» узел не будет удален полностью - он может быть переименован или изменен в другом размере, или, по крайней мере, его содержимое все еще может быть включено в вывод.

  4. Вполне вероятно, что с вашим пониманием проблемы становится все более и более ясным, три списка будут постоянно расти , поэтому шаблон соответствия для шаблона удаления черного списка будет изменен на разместить недавно обнаруженные элементы в черном списке. Недавно обнаруженные узлы из белого списка вообще не требуют работы. Только обработка новых элементов, занесенных в серый список (если таковые вообще обнаружены), потребует немного больше работы.

2 голосов
/ 03 февраля 2011

Решение Димитра Новатчева является более «чистым» и элегантным, но если вам нужно решение «белого списка» (потому что вы не можете предсказать, какой контент пользователи могут вводить, что вам нужно будет «внести в черный список»), тогда вам нужно будетполностью конкретизировать «белый список».

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:svg="http://www.w3.org/2000/svg">
    <xsl:output indent="yes" />

    <!--The "whitelist" template that will copy matched nodes forward and apply-templates
        for any attributes or child nodes -->
    <xsl:template match="svg:svg 
        | svg:defs  | svg:defs/text()
        | svg:g  | svg:g/text()
        | svg:a  | svg:a/text()
        | svg:use   | svg:use/text()
        | svg:rect  | svg:rect/text()
        | svg:circle  | svg:circle/text()
        | svg:ellipse  | svg:ellipse/text()
        | svg:line  | svg:line/text()
        | svg:polyline  | svg:polyline/text()
        | svg:polygon  | svg:polygon/text()
        | svg:path  | svg:path/text()
        | svg:text  | svg:text/text()
        | svg:tspan  | svg:tspan/text()
        | svg:tref  | svg:tref/text()
        | svg:textpath  | svg:textpath/text()
        | svg:linearGradient  | svg:linearGradient/text()
        | svg:radialGradient  | svg:radialGradient/text()
        | svg:clippath  | svg:clippath/text()
        | svg:text | svg:text/text()">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates select="node()" />
        </xsl:copy>
    </xsl:template>

    <!--The "blacklist" template, which does nothing except apply templates for the 
        matched node's attributes and child nodes -->
    <xsl:template match="@* | node()">
        <xsl:apply-templates select="@* | node()" />
    </xsl:template>

</xsl:stylesheet>
1 голос
/ 03 февраля 2011

svgfig - хороший инструмент для этой работы. Вы можете загружать файлы SVG и выбирать нужные вам части для создания нового документа. Или вы можете просто удалить части, которые вам не нравятся, и заново сохранить.

0 голосов
/ 03 февраля 2011

В качестве альтернативы принятому XSLT-ответу вы можете использовать Ruby и Nokogiri :

require 'nokogiri'
svg = Nokogiri::XML( IO.read( "myfile.svg" ) )
svg.xpath( '//*[not(name()="rect" or name()="circle" or ...)]' ).each do |node|
  node.remove
end
File.open( "myfile_clean.svg", "w" ) do |file|
  file << svg.to_xml
end
...