【问题标题】:Access deep nested node from document.xml using nokogiri使用 nokogiri 从 document.xml 访问深层嵌套节点
【发布时间】:2016-08-28 11:09:04
【问题描述】:

我正在使用 nokogiri 访问 docx 的文档 xml 文件。

这是一个示例:

<w:document>
    <w:body>
        <w:p w:rsidR="00454EDC" w:rsidRDefault="00454EDC" w:rsidP="00454EDC">
                <w:drawing>
                    <wp:inline distT="0" distB="0" distL="0" distR="0">
                        <wp:extent cx="1926590" cy="1088571"/>
                        <wp:effectExtent l="0" t="0" r="0" b="0"/>
                        <wp:docPr id="1" name="Picture 1"/>
                        <wp:cNvGraphicFramePr>
                            <a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
                        </wp:cNvGraphicFramePr>
                        <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
                            <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                                <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                                    <pic:nvPicPr>
                                        <pic:cNvPr id="0" name="Picture 1"/>
                                        <pic:cNvPicPr>
                                            <a:picLocks noChangeAspect="1" noChangeArrowheads="1"/>
                                        </pic:cNvPicPr>
                                    </pic:nvPicPr>
                                    <pic:blipFill>
                                        <a:blip r:embed="rId5" cstate="print">
                                            <a:extLst>
                                                <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
                                                    <a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>
                                                </a:ext>
                                            </a:extLst>
                                        </a:blip>
                                        <a:srcRect/>
                                        <a:stretch>
                                            <a:fillRect/>
                                        </a:stretch>
                                    </pic:blipFill>
                                    <pic:spPr bwMode="auto">
                                        <a:xfrm>
                                            <a:off x="0" y="0"/>
                                            <a:ext cx="1951299" cy="1102532"/>
                                        </a:xfrm>
                                        <a:prstGeom prst="rect">
                                            <a:avLst/>
                                        </a:prstGeom>
                                        <a:noFill/>
                                        <a:ln>
                                            <a:noFill/>
                                        </a:ln>
                                    </pic:spPr>
                                </pic:pic>
                            </a:graphicData>
                        </a:graphic>
                    </wp:inline>
                </w:drawing>
            </w:p>
    </w:body>
</w:document>

现在我想访问所有&lt;w:drawing&gt; 标签,并从中访问&lt;a:blip&gt; 标签并从中提取r:embed 的属性值。

在这种情况下,您可以看到它是rId5

我可以使用xml.xpath('//w:drawing') 访问&lt;w:drawing&gt; 标签,但是当我这样做xml.xpath('//w:drawing').xpath('//a:blip') 时,它会抛出错误:

Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: //a:blip

我做错了什么,谁能指出我正确的方向?

【问题讨论】:

    标签: ruby xml xml-parsing nokogiri docx


    【解决方案1】:

    错误告诉您,在您的 XPath 查询中,//a:blip,Nokogiri 不知道 a 指的是什么命名空间。您需要指定在查询中定位的命名空间,而不仅仅是前缀。在文档中定义前缀 a 的事实并不重要,重要的是实际的命名空间 URI。只要命名空间 URI 匹配,就可以在查询中使用与文档中使用的完全不同的前缀。

    您可能想知道为什么查询 //w:drawing 有效。您没有包含完整的 XML,但我怀疑 w 前缀是在根节点上定义的(类似于 xmlns:w="http://some.uri.here")。如果您未指定任何命名空间,Nokogiri 将自动注册根节点中定义的任何名称空间,以便它们在您的查询中可用。 a 前缀对应的命名空间没有在根上定义,所以它不可用,所以你会看到你看到的错误。

    要在 Nokogiri 中指定命名空间,您需要传递一个哈希,将前缀(在 查询 中使用)映射到命名空间 URI,到 xpath 方法(或您正在使用的任何查询方法)。由于您提供自己的命名空间映射,因此您还需要包含您从根节点使用的任何名称,在这种情况下 Nokogiri 不包含它们。

    在您的情况下,代码如下所示:

    namespaces = {
      'w' => 'http://some.uri', # whatever the URI is for this namespace
      'a' => 'http://schemas.openxmlformats.org/drawingml/2006/main'
    }
    
    # You can combine this to a single query.
    # Also note you don’t want a double slash infront of
    # the `/a:blip` part, just one.
    xml.xpath('//w:drawing/a:blip', namespaces)
    

    查看Nokogiri tutorial section on namespaces 了解更多信息。

    【讨论】:

    • 对于像我这样的初学者来说很好的解释,谢谢 :)
    【解决方案2】:

    我会说这是您正在使用的 xml 解析器中的一个错误:

    确实,错误似乎是命名空间前缀a 未定义,但是,它已在&lt;a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"&gt; 中定义,它是&lt;a:blip&gt; 元素的父级。

    See here if you want to know more about xml namespaces

    似乎它们是关于 nokogiri 中命名空间前缀问题的其他一些问题,例如:Undefined namespace prefix in Nokogiri and XPath

    【讨论】:

      猜你喜欢
      • 2020-12-15
      • 2021-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-21
      • 2016-02-13
      • 2020-02-25
      • 1970-01-01
      相关资源
      最近更新 更多