选择具有特定命名空间属性的元素

发布于 2024-12-13 15:13:07 字数 2845 浏览 2 评论 0原文

我的问题具体是关于我在解析 Inkscape (XML) 文件时遇到的一些问题,但它的解决方案应该适用于任何 XML 文档,所以我觉得它与 Stackoverflow 相关。

我正在尝试使用 Nokogiri CSS 选择器来获取具有属性 inkscape:groupmode="layer" 的所有 元素。但是冒号导致了错误:

Nokogiri::CSS::SyntaxError: unexpected ':' after 'inkscape'

我的 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="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="744.09448819" height="1052.3622047" id="svg3720" version="1.1" inkscape:version="0.48.1 r9760" sodipodi:docname="test.svg">
  <defs id="defs3722">
    <inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:persp3d-origin="372.04724 : 350.78739 : 1" id="perspective3728"/>
  </defs>
  <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.35" inkscape:cx="375" inkscape:cy="634.28571" inkscape:document-units="px" inkscape:current-layer="g2818" showgrid="false" inkscape:window-width="550" inkscape:window-height="483" inkscape:window-x="66" inkscape:window-y="471" inkscape:window-maximized="0"/>
  <metadata id="metadata3725">
    <rdf:RDF>
      <cc:Work rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
        <dc:title/>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1">
    <rect style="fill:#d2e149;fill-opacity:1;stroke:none" id="rect2812" width="211.42857" height="128.57143" x="168.57143" y="215.21933" ry="64.285713"/>
  </g>
  <g inkscape:label="Layer 1 copy copy" inkscape:groupmode="layer" id="g2818">
    <rect style="fill:#d2e149;fill-opacity:1;stroke:none" id="rect2820" width="211.42857" height="128.57143" x="145.71428" y="615.2193" ry="64.285713"/>
  </g>
</svg>

我的选择器看起来像:

nokogiri_document.css('[inkscape:groupmode="layer"]').to_html

我还尝试用管道替换冒号

如何编写 CSS 选择器以在 inkscape:groupmode 属性上工作...或者就此而言任何 foo:bar 属性?

My problem is specifically about some trouble I'm having parsing an Inkscape (XML) file, but it's solution should be applicable to any XML doc, so I feel it's Stackoverflow relevant.

I'm trying to use the Nokogiri CSS selectors to get all the <g> elements that have the attribute inkscape:groupmode="layer". But the colon is causing the error:

Nokogiri::CSS::SyntaxError: unexpected ':' after 'inkscape'

My XML document looks like:

<?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="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="744.09448819" height="1052.3622047" id="svg3720" version="1.1" inkscape:version="0.48.1 r9760" sodipodi:docname="test.svg">
  <defs id="defs3722">
    <inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:persp3d-origin="372.04724 : 350.78739 : 1" id="perspective3728"/>
  </defs>
  <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.35" inkscape:cx="375" inkscape:cy="634.28571" inkscape:document-units="px" inkscape:current-layer="g2818" showgrid="false" inkscape:window-width="550" inkscape:window-height="483" inkscape:window-x="66" inkscape:window-y="471" inkscape:window-maximized="0"/>
  <metadata id="metadata3725">
    <rdf:RDF>
      <cc:Work rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
        <dc:title/>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1">
    <rect style="fill:#d2e149;fill-opacity:1;stroke:none" id="rect2812" width="211.42857" height="128.57143" x="168.57143" y="215.21933" ry="64.285713"/>
  </g>
  <g inkscape:label="Layer 1 copy copy" inkscape:groupmode="layer" id="g2818">
    <rect style="fill:#d2e149;fill-opacity:1;stroke:none" id="rect2820" width="211.42857" height="128.57143" x="145.71428" y="615.2193" ry="64.285713"/>
  </g>
</svg>

My selector looks like:

nokogiri_document.css('[inkscape:groupmode="layer"]').to_html

I also tried replacing the colon with a pipe

How do I write the CSS selector to work on the inkscape:groupmode attribute...or for that matter any foo:bar attribute?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

顾挽 2024-12-20 15:13:07

使用 XPath,指定 g 元素的命名空间。由于您的根元素将 xmlns:svg 声明为与新的默认命名空间 (xmlns) 相同,因此您可以使用 svg 作为前缀:

require 'nokogiri'
doc = Nokogiri.XML(IO.read('contents.xml'))
layers = doc.xpath('//svg:g[@inkscape:groupmode="layer"]')

p layers.map{ |layer| layer['id'] }
#=> ["layer1", "g2818"]

解码后,上面的 XPath 表示:

  • // - 在文档的任何级别
  • svg:g - …find具有命名空间的 g 元素匹配 svg 命名空间
  • […] - …但前提是满足此内容
  • @inkscape:groupmode< /code>- …有一个名为 groupmode 的属性 (@),其命名空间与 inkscape
  • ="layer" - 该属性的内在价值是文本

或者,如果您只是尝试读取此文件(而不是操作并重新保存它),您可以使用删除所有名称空间的粗略但简化的技巧。在这种情况下,您的原始代码的工作原理很简单:

doc.remove_namespaces!
p doc.css('g[groupmode="layer"]').map{ |g| g['id'] }
#=> ["layer1", "g2818"]

Use XPath, specifying the namespace for the g elements. Since your root element declares the xmlns:svg to be the same as the new default namespace (xmlns) you can use svg as your prefix:

require 'nokogiri'
doc = Nokogiri.XML(IO.read('contents.xml'))
layers = doc.xpath('//svg:g[@inkscape:groupmode="layer"]')

p layers.map{ |layer| layer['id'] }
#=> ["layer1", "g2818"]

Decoded, the above XPath says:

  • // - At any level of the document
  • svg:g - …find g elements with a namespace matching the svg namespace
  • […] - …but only if the contents of this are met
  • @inkscape:groupmode - …there is an attribute (@) named groupmode with a namespace matching inkscape
  • ="layer" - and the intrinsic value of this attribute is the text layer.

Alternatively, if you're just trying to read this file (and not manipulate and re-save it) you can use the gross-but-simplifying hack of removing all namespaces. In this case, your original code works simply:

doc.remove_namespaces!
p doc.css('g[groupmode="layer"]').map{ |g| g['id'] }
#=> ["layer1", "g2818"]
吃不饱 2024-12-20 15:13:07

我建议你尝试使用XPath。看这个片段:

require 'nokogiri'
doc = Nokogiri::XML(File.read('your_file.xml'))
doc.xpath('//xmlns:g[starts-with(@inkscape:label, "Layer")]').size  # => 2

请注意XPath表达式中的xmlns。由于 XPath 查询查找不在任何命名空间中的元素,因此您需要告诉 XPath 处理器您正在给定命名空间中查找元素。您可以通过多种方式做到这一点。我使用最简单的情况 - 在 XPath 查询中使用默认名称空间。您还可以在 XPath 方法调用的第二个参数中定义自定义命名空间,并在查询中使用它。

I suggest that you try to use XPath. Look at this snippet:

require 'nokogiri'
doc = Nokogiri::XML(File.read('your_file.xml'))
doc.xpath('//xmlns:g[starts-with(@inkscape:label, "Layer")]').size  # => 2

Please pay attention at xmlns in XPath expression. Because XPath query looks for elements that are not in any namespace, you need to tell your XPath processor that you are looking for elements in given namespace. You can do this by several ways. I use most simple case - the using the default namespace in XPath query. Also you can define a custom namespace in the second argument of the XPath method call and use that in the query.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文