【问题标题】:PHP SVG editingPHP SVG 编辑
【发布时间】:2017-05-06 22:48:15
【问题描述】:

例如,我试图从 svg 中读取样式块,我可以获取类型但不能获取字符串。

$svgTemplate = new SimpleXMLElement($_POST['SvgTemplateImport']);
$svgTemplate->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');
$svgTemplate->registerXPathNamespace('xlink', 'http://www.w3.org/1999/xlink');

//I tried a bunch of things and this how far I got
$test[] = $svgTemplate->xpath('/svg:svg/svg:style');
$test[] = $result[0][0]['type'];

var_dump($test);

如何检索样式字符串?
如何设置样式字符串?
如何复制组并更改其属性? (比如翻译 x 和 y)?

除其他外,我还想更改 svg 的分辨率和视图框,但我将能够从答案中找出这些。

谢谢。

编辑1: 查看我的 svg:我评论了我想要实现的目标。

<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" width="460px" height="200px" viewBox="0 0 460 200" style="enable-background:new 0 0 460 200;" xml:space="preserve">
<style type="text/css">/* new style */</style>
<!-- I did cut the unrelevant parts out-->
<symbol id="MoonFull" viewBox="0 0 100 100">
    <path style="fill:#FFFFFF;" d="M50,99.33C22.8,99.33,0.67,77.2,0.67,50S22.8,0.67,50,0.67S99.33,22.8,99.33,50S77.2,99.33,50,99.33   z"/>
    <path style="fill:#231F20;" d="M50,1.35c26.83,0,48.65,21.82,48.65,48.65S76.83,98.65,50,98.65S1.35,76.83,1.35,50   S23.17,1.35,50,1.35 M50,0C22.39,0,0,22.39,0,50s22.39,50,50,50s50-22.39,50-50S77.61,0,50,0L50,0z"/>
</symbol>
<symbol id="Star" viewBox="0 0 100 100">
    <path id="Star" style="fill:#00FF00;" d="M50,3.58L62.5,39H100L70.83,60.95l10.42,34.93L50,74.81L18.75,95.53l10.42-34.51L0,39  h37.5L50,3.58z"/>
</symbol>
<g id="TemplateForm">
    <g id="twd">
        <rect id="twdCanvas" x="7.3" y="9.32" class="st0" width="263.03" height="72"/>
        <text id="twdWeekdayshorttext" transform="matrix(1 0 0 1 249.5817 41.9174)"><tspan x="0" y="0" class="st2 st3">C</tspan><tspan x="-1.2" y="29.13" class="st2 st3">S</tspan></text>
        <text id="twdDatenumber" transform="matrix(1 0 0 1 41.5544 69.5698)" class="st5 st6">26</text>
        <line id="twdDivider" class="st7" x1="126.49" y1="9.32" x2="126.49" y2="81.32"/>
        <g id="twdText">
            <text id="twdTextLine3" transform="matrix(1 0 0 1 135.0475 28.1718)" class="st2 st8">1234567890abcdef12345</text>
            <text id="twdTextLine2" transform="matrix(1 0 0 1 135.0475 41.5319)" class="st2 st8">1234567890abcdef12345</text>
            <text id="twdTextLine1" transform="matrix(1 0 0 1 135.0475 54.892)" class="st2 st8">1234567890abcdef12345</text>
            <text id="twdTextLine0" transform="matrix(1 0 0 1 135.0475 68.252)" class="st2 st8">1234567890abcdef12345</text>
        </g>
        <line id="twdDateNumAliignerLeft" class="st0" x1="120.02" y1="17.39" x2="120.02" y2="72.07"/>
        <rect id="twdBoxStar" x="15.68" y="19.75" class="st0" width="21" height="21"/>
        <rect id="twdBoxText" x="132.49" y="17.39" class="st0" width="107.92" height="54.68"/>
        <rect id="twdBoxMoon" x="15.68" y="49.15" class="st0" width="21" height="21"/>
    </g>
    <g id="tcl">
        <rect id="tclCanvas" x="7.3" y="153.31" class="st0" width="263.03" height="36"/>
        <line id="tclDivider" class="st7" x1="126.49" y1="153.31" x2="126.49" y2="189.31"/>
        <text id="tclYear" transform="matrix(1 0 0 1 59.1393 183.5269)" class="st2 st9">YYYY</text>
        <text id="tclMonthname" transform="matrix(1 0 0 1 130.9372 182.7798)" class="st2 st10">monthname</text>
    </g>
</g>
<g id="result"><!-- this group will be generated -->
    <!-- this is made from: #twd and added transformation-->
    <g id="result1" transform="matrix(1 0 0 1 249.5817 41.9174)">
        <rect id="twdCanvas" x="7.3" y="9.32" class="st0" width="263.03" height="72"/>
        <!-- all the texts will be canged -->
        <text id="twdWeekdayshorttext" transform="matrix(1 0 0 1 249.5817 41.9174)"><tspan x="0" y="0" class="st2 st3">C</tspan><tspan x="-1.2" y="29.13" class="st2 st3">S</tspan></text>
        <text id="twdDatenumber" transform="matrix(1 0 0 1 41.5544 69.5698)" class="st5 st6">26</text>
        <line id="twdDivider" class="st7" x1="126.49" y1="9.32" x2="126.49" y2="81.32"/>
        <g id="twdText">
            <text id="twdTextLine3" transform="matrix(1 0 0 1 135.0475 28.1718)" class="st2 st8">changed this</text>
            <text id="twdTextLine2" transform="matrix(1 0 0 1 135.0475 41.5319)" class="st2 st8">changed this</text>
            <text id="twdTextLine1" transform="matrix(1 0 0 1 135.0475 54.892)" class="st2 st8">changed this</text>
            <text id="twdTextLine0" transform="matrix(1 0 0 1 135.0475 68.252)" class="st2 st8">changed this</text>
        </g>
        <line id="twdDateNumAliignerLeft" class="st0" x1="120.02" y1="17.39" x2="120.02" y2="72.07"/>
        <rect id="twdBoxText" x="132.49" y="17.39" class="st0" width="107.92" height="54.68"/>

        <!-- this: <rect id="twdBoxStar" x="15.68" y="19.75" class="st0" width="21" height="21"/> to: -->
        <use x="132.49" y="17.39" width="21" height="21" xlink:href="#Star" /><!-- how can I chnage the fill color? -->

        <!-- this: <rect id="twdBoxMoon" x="15.68" y="49.15" class="st0" width="21" height="21"/> to: -->
        <use x="15.68" y="49.15" width="21" height="21" xlink:href="#MoonFull" />
    </g>
    <!-- and so on... the end I have to adjust the viewbox and resolution-->
</g>
</svg>

【问题讨论】:

  • “如何复制一个组并更改其属性?” - 你的意思是一组元素吗?
  • 一个 svg 组: ... ,并使其 ... 我猜同样的方法适用于所有标签,这就是我问这个例子的原因。抱歉不能编辑 cmets:(

标签: php xml dom svg simplexml


【解决方案1】:

修改现有结构

$svg_data = <<<'SVG'
<svg xmlns:svg="http://www.w3.org/2000/svg">
  <svg:style>
    circle { fill: orange; stroke: black; }
  </svg:style>
  <svg:g id="group-a" stroke="green" fill="white" stroke-width="5">
     <circle cx="25" cy="25" r="15"/>
     <circle cx="40" cy="25" r="15"/>
  </svg:g>
  <svg:g id="group-b" stroke="red" fill="blue" stroke-width="1">
     <circle cx="10" cy="80" r="15"/>
  </svg:g>
</svg>
SVG;

$svgTemplate = new SimpleXMLElement($svg_data);
$svgTemplate->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');

// How to retrieve the style string
$style = $svgTemplate->xpath('svg:style');
printf("Original style:\n%s\n\n", (string)$style[0]);

// How to set the style string
$children = $svgTemplate->children('svg', true);
$children->style = '/* new style */';

// How to copy a group and change attributes on it (like translate x and y)
$group_a = $svgTemplate->xpath('svg:g[@id="group-a"]');
if (isset($group_a[0])) {
  $group_a[0]->addAttribute('transform', 'translate(30) rotate(45 50 50)');
}

printf("Modified XML:\n%s\n", $svgTemplate->asXML());

输出

Original style:

    circle { fill: orange; stroke: black; }


Modified XML:
<?xml version="1.0"?>
<svg xmlns:svg="http://www.w3.org/2000/svg">
  <svg:style>/* new style */</svg:style>
  <svg:g id="group-a" stroke="green" fill="white" stroke-width="5" transform="translate(30) rotate(45 50 50)">
     <circle cx="25" cy="25" r="15"/>
     <circle cx="40" cy="25" r="15"/>
  </svg:g>
  <svg:g id="group-b" stroke="red" fill="blue" stroke-width="1">
     <circle cx="10" cy="80" r="15"/>
  </svg:g>
</svg>

说明

节点值是通过casting对象的casting获取到字符串的。这是可能的,因为SimpleXMLElement 实现了__toString 方法。

由于children方法通过引用返回节点对象,所以可以通过修改该方法返回的值来修改原来的结构。请注意,您应该在适当的时候将注册的命名空间传递给children 方法。

要添加属性,您需要获取节点(例如,使用 xpath 方法)并在此节点的上下文中调用 addAttribute 方法。

SimpleXMLElement 的方法(例如xpathchildrenattributes)返回一组匹配元素作为SimpleXMLElement 对象。您可以通过索引(例如$style[0])或名称($children-&gt;style)访问它们。您也可以使用foreach 对其进行迭代。

克隆、修改和附加节点

据我所知,如果不手动进行深层复制,就不可能将SimpleXMLElement 节点附加到文档中。您可以通过递归迭代节点并调用addChild 方法来进行深层复制。但是有一种简单的方法可以使用 DOM 扩展来执行此操作:

$svg = new SimpleXMLElement($svg_data);
$svg->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');

$g_tpl = $svg->xpath('svg:g[@id="TemplateForm"]');
if (!isset($g_tpl[0])) {
  die("#TemplateForm group not found\n");
}

$g_res = clone $g_tpl[0];
$g_res['id'] = 'result';

$g_twd = $g_res->g[0];
$g_twd['id'] = 'result1';
$g_twd['transform'] = 'matrix(1 0 0 1 249.5817 41.9174)';

// Change the rest of the nodes in similar manner.
// Then add $g_res to the root node. You will need DOM extension for this.
$dom_res = dom_import_simplexml($g_res);
$dom_svg = dom_import_simplexml($svg);
$dom_svg->appendChild($dom_res);

echo $svg->asXML();

考虑使用 DOM 扩展

一般来说,如果您需要对相对较小的文档(例如 SVG)执行复杂的 DOM 操作,请使用 DOM 扩展而不是 SimpleXML。

示例

$doc = new DOMDocument;
$doc->loadXML($svg_data);
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('svg', 'http://www.w3.org/2000/svg');

$g_res = $doc->createElement('g');
$g_res->setAttribute('id', 'result');

$g_twd_list = $xpath->query('svg:g[@id="TemplateForm"]/svg:g[@id="twd"]');

$g_twd = clone $g_twd_list[0];
$g_twd->setAttribute('id', 'result1');
$g_twd->setAttribute('transform', 'matrix(1 0 0 1 249.5817 41.9174)');
$g_res->appendChild($g_twd);

$doc->firstChild->appendChild($g_res);
echo $doc->saveXML();

【讨论】:

  • 我是否需要在字符串中包含
  • @z4k,当然你不需要这里的文档。只需将您的 SVG 字符串存储到 $svg_data 变量中,例如$svg_data = $_POST['SvgTemplateImport'];。为了清楚起见,我已经放置了示例 XML 输入。
  • 到目前为止一切顺利,如何选择克隆组的位置?之后如何更改嵌套在组中的文本值? “$children”不能用于所有这些吗?我有所有的 id 并且结构是已知的,我不需要找到具有 id 的组,它是一个固定的结构。如何做类似的事情:$children->groupId->otherGroupId->textValueById?我怎样才能 var dump $children,它应该有整个 svg,对吗?
  • 使用xpath方法获取g,如答案所示。您可以使用foreach 迭代children() 和嵌套的子节点,或者使用[](对于节点集)和-&gt;(对于节点)运算符访问节点。 SimpleXMLElement 上的 var_dump() 不显示对象中实际存储的值, - 您应该通过答案中描述的方法访问节点和属性。使用var_dump($object),您只能确定$object 是代表一组节点还是单个节点。
  • 我以为我明白了,但没有。您可以从我添加到问题中的 svg 中发布一个示例吗?克隆并更改 1 个值和 1 个属性。请参阅 。感谢您的努力和时间。
猜你喜欢
  • 2016-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-06
相关资源
最近更新 更多