使用 nokogiri 从 document.xml 访问深层嵌套节点
Access deep nested node from document.xml using nokogiri
我正在使用 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>
现在我想访问所有 <w:drawing>
标签,我想从它们访问 <a:blip>
标签并从中提取 r:embed 的属性值。
在这种情况下,如您所见,它是 rId5
我可以使用 xml.xpath('//w:drawing')
访问 <w:drawing>
标签,但是当我这样做时 xml.xpath('//w:drawing').xpath('//a:blip')
,它会抛出错误:
Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: //a:blip
我做错了什么,谁能指出我正确的方向?
我会说这是您正在使用的 xml 解析器中的错误:
确实,错误似乎是命名空间前缀 a
未定义,然而,它已在 <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
中定义,它是 <a:blip>
元素的父元素。
See here if you want to know more about xml namespaces
似乎是关于nokogiri中命名空间前缀问题的其他一些问题,例如:Undefined namespace prefix in Nokogiri and XPath
错误告诉您,在您的 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 了解更多信息。
我正在使用 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>
现在我想访问所有 <w:drawing>
标签,我想从它们访问 <a:blip>
标签并从中提取 r:embed 的属性值。
在这种情况下,如您所见,它是 rId5
我可以使用 xml.xpath('//w:drawing')
访问 <w:drawing>
标签,但是当我这样做时 xml.xpath('//w:drawing').xpath('//a:blip')
,它会抛出错误:
Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: //a:blip
我做错了什么,谁能指出我正确的方向?
我会说这是您正在使用的 xml 解析器中的错误:
确实,错误似乎是命名空间前缀 a
未定义,然而,它已在 <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
中定义,它是 <a:blip>
元素的父元素。
See here if you want to know more about xml namespaces
似乎是关于nokogiri中命名空间前缀问题的其他一些问题,例如:Undefined namespace prefix in Nokogiri and XPath
错误告诉您,在您的 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 了解更多信息。