【问题标题】:SVG via dynamic XML+XSLSVG 通过动态 XML+XSL
【发布时间】:2023-04-02 14:55:01
【问题描述】:

这是一个有点模糊的概念,我一直在脑海中闪过,我很好奇是否有一种优雅的解决方法。也许应该把它当作一个思想实验。

假设您有一个带有相应 XSL 转换的 XML 模式,它在浏览器中将 XML 呈现为 SVG。 XSL 使用适当的 Javascript 处理程序生成 SVG,最终实现类似编辑的功能,以便用户可以编辑对象的属性或其在 SVG 画布上的位置。例如,一个元素可以从一个位置拖到另一个位置。

现在,这并不是特别困难 - 拖放示例只是更改 SVG 对象的 (x,y) 坐标的问题,或者调整大小操作只是更改其宽度或高度的简单问题.

但是有没有一种优雅的方式让 Javascript 在 source XML 文档的 DOM 上而不是渲染的 SVG 上工作?你为什么问?好吧,假设您有非常复杂的 XSL 转换,其中一个属性的修改会导致 SVG 的复杂更改。您希望保持 Javascript 代码的简单性,同时也是一种将修改后的 XML 持久保存回服务器的简单方法。

这可能如何发挥作用的一些可能性:

  1. 修改源 DOM 后,只需重新运行 XSL 转换并替换原来的即可。 缺点:蛮力,潜在的昂贵操作。
  2. 在源 XML/SVG 和目标 XML/SVG 中创建 id/class 命名约定,以便元素可以相互关联,并仅对新 DOM 的一个子集进行 XSL 转换。换句话说,修改临时 DOM,对其应用 XSL,从 SVG 中删除更改的元素,然后插入新元素。 缺点:可能无法将 XSL 应用于临时的浏览器内 DOM(?)。此外,维护起来可能有点复杂或难看。

我认为有可能提出一个处理第二种情况的框架,但挑战在于使其轻量级并且不与实际的 XML 模式密切相关。有什么想法或其他可能性吗?或者是否有一种我不知道的现有方法?

更新:为了澄清,正如我在下面的评论中提到的,这有助于将绘制代码与编辑代码分开。有关这如何有用的更具体示例,请想象一个元素,该元素根据相邻元素的属性值确定它的绘制方式。最好直接在绘制代码中压缩该逻辑,而不是在编辑代码中复制它。

【问题讨论】:

    标签: javascript xml xslt dynamic svg


    【解决方案1】:

    也许可以使用 AJAX:不是在本地编辑文档,而是将原始 XML 的编辑命令发送到服务器,服务器再次转换,然后将新的 SVG 发回。

    这里的主要问题是当您更新当前页面上的 SVG 元素时会发生什么。拖放仍然感觉流畅吗?如果没有,那么您可能不得不采用两种方法的混合:使用 JavaScript 拖动 SVG 节点,当用户放下节点时,将更新发送到服务器以获取新的 SVG。

    您将希望避免尝试在 XML 和本地 SVG 中同步更新(这意味着在 JavaScript 中复制部分 XSLT -> 留在一个世界,不要混用)。

    【讨论】:

    • 不过,主要思想是浏览器将处理转换并在进行更改后立即更新,包括(正如您提到的)需要像拖放一样平滑的编辑。优点是您将绘制代码隔离到一个转换中,编辑代码可能完全不知道。
    • 我明白;我只是怀疑视觉反馈是否会在重新运行局部变换后幸存下来。最重要的是,我无法告诉浏览器再次应用转换:当您的 JS 运行时,您不再拥有原始文档,因为它已经被转换并且浏览器不保留副本。跨度>
    • 好吧,您可以手动加载 XML,保留一份副本,然后使用 transformNode() 或 javascript 库在 Javascript 中应用 xslt...然后手动将其添加到您的 dom。但正如你所说,问题在于速度。
    【解决方案2】:

    我们在浏览器内的 XML 编辑器 Xopus 中完成了这项工作。你可以看到一个例子here。 我们加载 XML 源文档、一个 XML Schema 和一个输出 HTML+SVG 的 XSLT。在内部,我们将您的 XSLT 重写为 XSLT',这将允许我们将输出 HTML+SVG 跟踪回原始 XML,该 XML 是 XSL 中输出该 HTML 或 SVG 节点的上下文。这就是您所指的框架。

    为了便于编辑,我们将光标放在您的 XSLT 输出上,并在您键入或插入元素时更新 XML DOM。每次更改后,我们将重新运行 XSLT。出于性能原因,我们会将 XSLT 输出与之前的输出进行比较,并使用 HTML DOM 操作将更改应用到所见即所得视图。

    我们使用另一个 XSLT 来区分两个 XSLT 输出。我们可以这样做是因为我们已经修改了原始 XSLT(导致 XSLT'),以便为每个输出节点输出唯一且持久的 ID。所以所有新节点都会有新的 ID,缺少的 ID 会被移除。

    XSLT' 是您提供的原始 XSLT 的重写版本。它仍然是 XSLT,但我们添加了一些东西,所以它输出所有输出节点的 ID(我们使用另一个 XSLT 这样做)。除此之外,它在功能上等同于您原来的 XSLT。

    【讨论】:

    • 很高兴听到它是可行的。你如何区分两个 XSLT 输出?
    • 或者,还有,XSLT' 是什么意思?你在内部做的事情,还是我找不到的既定标准?
    • 我们使用另一个 XSLT 来区分两个 XSLT 输出。我们可以这样做是因为我们已经修改了原始 XSLT(导致 XSLT'),以便为每个输出节点输出唯一且持久的 ID。所以所有新节点都会有新的 ID,缺少的 ID 会被移除。
    • XSLT' 是您提供的原始 XSLT 的重写版本。它仍然是 XSLT,但我们添加了一些东西,所以它输出所有输出节点的 ID(我们使用另一个 XSLT 这样做)。除此之外,它在功能上等同于您原来的 XSLT。
    • 这很聪明。我想看看 XSL,但这是另一个问题。希望您不介意,但我将您的 cmets 添加到了答案中。如果您想详细说明 diff XSL,非常欢迎 :)
    猜你喜欢
    • 1970-01-01
    • 2017-01-26
    • 2016-03-13
    • 1970-01-01
    • 2015-06-05
    • 1970-01-01
    • 1970-01-01
    • 2015-03-27
    • 2014-07-16
    相关资源
    最近更新 更多