选择具有特定命名空间属性的元素
我的问题具体是关于我在解析 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用 XPath,指定
g
元素的命名空间。由于您的根元素将xmlns:svg
声明为与新的默认命名空间 (xmlns
) 相同,因此您可以使用svg
作为前缀:解码后,上面的 XPath 表示:
//
- 在文档的任何级别svg:g
- …find具有命名空间的g
元素匹配svg
命名空间[…]
- …但前提是满足此内容@inkscape:groupmode< /code>
- …有一个名为
groupmode
的属性 (@
),其命名空间与inkscape
="layer"
- 该属性的内在价值是文本层
。或者,如果您只是尝试读取此文件(而不是操作并重新保存它),您可以使用删除所有名称空间的粗略但简化的技巧。在这种情况下,您的原始代码的工作原理很简单:
Use XPath, specifying the namespace for the
g
elements. Since your root element declares thexmlns:svg
to be the same as the new default namespace (xmlns
) you can usesvg
as your prefix:Decoded, the above XPath says:
//
- At any level of the documentsvg:g
- …findg
elements with a namespace matching thesvg
namespace[…]
- …but only if the contents of this are met@inkscape:groupmode
- …there is an attribute (@
) namedgroupmode
with a namespace matchinginkscape
="layer"
- and the intrinsic value of this attribute is the textlayer
.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:
我建议你尝试使用XPath。看这个片段:
请注意XPath表达式中的
xmlns
。由于 XPath 查询查找不在任何命名空间中的元素,因此您需要告诉 XPath 处理器您正在给定命名空间中查找元素。您可以通过多种方式做到这一点。我使用最简单的情况 - 在 XPath 查询中使用默认名称空间。您还可以在 XPath 方法调用的第二个参数中定义自定义命名空间,并在查询中使用它。I suggest that you try to use XPath. Look at this snippet:
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.