【问题标题】:How to write xpath query with default namespace and attribute condition [closed]如何使用默认命名空间和属性条件编写 xpath 查询 [关闭]
【发布时间】:2013-04-18 11:19:13
【问题描述】:

我有这样的xml:

<?xml version="1.0"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
      <Worksheet ss:Name="Name1">
        something
      </Worksheet>
      <Worksheet ss:Name="Name2">
        something else
      </Worksheet>
    </Workbook>

查询的外观应该如何将我变成具有 ss:Name 属性 Name1 的 Worksheet 元素。由于默认命名空间,我必须像这样设置第一个条件:

//*[name()="Worksheet"]

但我不知道如何添加属性条件...

------- 更新 ------- 因为这里找不到解决办法都是xml文件(excel生成的文件):

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
  <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
    <Author>Don diego</Author>
    <LastAuthor>Don diego</LastAuthor>
    <Created>2013-04-18T07:20:33Z</Created>
    <LastSaved>2013-04-18T07:20:33Z</LastSaved>
    <Company>CEI</Company>
    <Version>14</Version>
  </DocumentProperties>
  <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
    <AllowPNG/>
  </OfficeDocumentSettings>
  <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
    <WindowHeight>7740</WindowHeight>
    <WindowWidth>13395</WindowWidth>
    <WindowTopX>360</WindowTopX>
    <WindowTopY>30</WindowTopY>
    <ProtectStructure>False</ProtectStructure>
    <ProtectWindows>False</ProtectWindows>
  </ExcelWorkbook>
  <Styles>
    <Style ss:ID="Default" ss:Name="Normal">
      <Alignment ss:Vertical="Bottom"/>
      <Borders/>
      <Font ss:FontName="Calibri" x:CharSet="238" x:Family="Swiss" ss:Size="11" ss:Color="#000000"/>
      <Interior/>
      <NumberFormat/>
      <Protection/>
    </Style>
  </Styles>
  <Worksheet ss:Name="Sheet1">
    <Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1" x:FullRows="1" ss:DefaultRowHeight="15"/>
    <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
      <PageSetup>
        <Header x:Margin="0.3"/>
        <Footer x:Margin="0.3"/>
        <PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
      </PageSetup>
      <Selected/>
      <Panes>
        <Pane>
          <Number>3</Number>
          <ActiveCol>1</ActiveCol>
        </Pane>
      </Panes>
      <ProtectObjects/>
      <ProtectScenarios/>
    </WorksheetOptions>
  </Worksheet>
  <Worksheet ss:Name="Sheet2">
    <Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1" x:FullRows="1" ss:DefaultRowHeight="15"/>
    <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
      <PageSetup>
        <Header x:Margin="0.3"/>
        <Footer x:Margin="0.3"/>
        <PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
      </PageSetup>
      <Selected/>
      <Panes>
        <Pane>
          <Number>3</Number>
          <ActiveCol>1</ActiveCol>
        </Pane>
      </Panes>
      <ProtectObjects/>
      <ProtectScenarios/>
    </WorksheetOptions>
  </Worksheet>
  <Worksheet ss:Name="Sheet3">
    <Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1" x:FullRows="1" ss:DefaultRowHeight="15"/>
    <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
      <PageSetup>
        <Header x:Margin="0.3"/>
        <Footer x:Margin="0.3"/>
        <PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
      </PageSetup>
      <Selected/>
      <Panes>
        <Pane>
          <Number>3</Number>
          <ActiveCol>1</ActiveCol>
        </Pane>
      </Panes>
      <ProtectObjects/>
      <ProtectScenarios/>
    </WorksheetOptions>
  </Worksheet>
</Workbook>

我想通过 XPath 获取具有属性“Sheet1”的 Worksheet 元素。 这就是我所拥有的:

$uri = $this->doc->getDocNamespaces()['']; //$this->doc is obiect of simplexmlelement class
$this->doc->registerXPathNamespace('default', $uri); //'urn:schemas-microsoft-com:office:spreadsheet'
$current_worksheet = $this->doc->xpath('/*/default:Worksheet[@ss:Name = "Sheet1"]');
die(var_dump($current_worksheet));//empty array :(

现在$current_worksheet是一个空数组:(看起来默认命名空间和ss命名空间一样(同一个瓮)?

【问题讨论】:

  • "dirty hack" is with local-name(),对于属性,您需要注册一个前缀,以便您可以将它与您的 xpath 一起使用。此外,您的 XML 文件 无效,根元素之前不能有空格,我将在您的问题中修复它,删除空格。
  • 这个xml只是简化,复制粘贴而成
  • &lt;Workbook&gt; 是文档元素吗?如果不是,这确实会有所不同,因此您应该明确说明,否则您要求的是错误的东西;)(我不是在问这是否是整个文档,只是第一个element 也是原始 XML 中的第一个元素)
  • 仔细检查您的示例。使用 XML 和您的代码(simplexml),它确实对我有用。你也不需要注册 default: 因为你可以使用 ss: 代替你写的。这也是我在回答中概述的方式。您可能在其他地方有一个小错误,xpath 有效:(
  • 嗯...问题可能出在我将这个属性添加到 xml 的方式上,我这样做是这样的 $ws = $this->doc->addChild('Worksheet'); $ws->addAttribute('xmlns:ss:Name', 'Sheet1');你怎么看?

标签: php xml xpath


【解决方案1】:
/*/ss:Worksheet[@ss:Name = "Name1"]

这里有两个选择。首先,我从我认为更正确的一个开始。它利用命名空间。要让它工作,您需要使用相应的 URI 注册命名空间前缀,这里有两个命名空间:

Prefix: default
URI   : urn:schemas-microsoft-com:office:spreadsheet

Prefix: ss
URI   : urn:schemas-microsoft-com:office:spreadsheet

然后你就可以查询了:

/*/default:Worksheet[@ss:Name = "Name1"]

第二个变体执行完全相同的 xpath 查询,但忽略了所有非默认命名空间的命名空间。这适用于local-name(),并且更复杂:

/*/*[local-name()="Worksheet"][@*[local-name()="Name" and . = "Name1"]]

如您所见,第一个变体更可取,因为它更具可读性。此外,它更加独特,因为它命名每个具体元素,而不仅仅是本地名称。

这是一个简短的示例,您可以如何注册一个 XML 命名空间前缀,以便它可以与 xpath 一起使用。这是必要的,因为默认命名空间是非空的:

$xml = simplexml_load_string($string);

$uri = $xml->getDocNamespaces()[''];
$xml->registerXPathNamespace('default', $uri);

$result = $xml->xpath('/*/default:Worksheet[@ss:Name = "Name1"]');

echo trim($result[0]), "\n"; # something

Online Demo - 值得记住:就像每个元素一样,每个属性也可以有自己的命名空间。属性命名空间不会自动成为元素命名空间(仅文档默认命名空间)。

【讨论】:

  • 我已经更新了我的问题,请看看有什么问题。
【解决方案2】:

更多类似的东西:

选择“Name”属性值为“Name1”的“Worksheet”元素。

//Worksheet[@ss:Name='Name1']

【讨论】:

  • 工作表属于默认命名空间,无法正常工作
【解决方案3】:
/x:Workbook/x:Worksheet[@ss:Name='Name1']

在调用应用程序中将命名空间前缀“x”和“ss”绑定到适当的命名空间 URI,使用您用于运行 XPath 的任何 API。

【讨论】:

    【解决方案4】:

    好吧,我找到了 hakre 的 xpath 对我不起作用的原因,我不知道为什么,但是这段代码

    $xml = <<<XML
    <?xml version="1.0"?>
    <?mso-application progid="Excel.Sheet"?>
    <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
    </Workbook>
    XML;
    $el = new SimpleXmlElement($xml);
    $child = $el->addChild('Worksheet');
    $child->addAttribute('xmlns:ss:Name', 'Sheet1');
    $result = $el->xpath("ss:Worksheet[@ss:Name='Sheet1']");
    

    没用。我必须创建新的 SimpleXMLElement 才能使其工作,如下所示:

    $xml = <<<XML
    <?xml version="1.0"?>
    <?mso-application progid="Excel.Sheet"?>
    <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
    </Workbook>
    XML;
    $el = new SimpleXmlElement($xml);
    $child = $el->addChild('Worksheet');
    $child->addAttribute('xmlns:ss:Name', 'Sheet1');
    $el = new SimpleXMLElement($el->asXML()); //refreshing of SimpleXMLElement
    $result = $el->xpath("ss:Worksheet[@ss:Name='Sheet1']"); //now it work like a charm
    

    谢谢你的帮助

    【讨论】:

    • 这行代码完全错误:$child-&gt;addAttribute('xmlns:ss:Name', 'Sheet1'); 请查阅手册,尤其是如何使用命名空间添加属性:php.net/simplexmlelement.addattribute -- 另外,您问的问题不是关于 DOM 操作,而是关于做 xpath 查询。如果你想知道一些事情,你应该问它,而不是关于其他事情;)
    • 我使用 addAttribute 是因为 $child->addAttribute('ss:Name', 'Sheet1', 'urn:schemas-microsoft-com:office:spreadsheet');使用默认命名空间添加索引属性('ss' 和 'default' 命名空间相同)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 2010-10-07
    • 2010-12-16
    相关资源
    最近更新 更多