2015-01-07 2 views
2

У меня проблема с Powershell и MSHTML: getElementById и getElementsByTagName дают мне разные результаты.Несоответствие между getElementById и getElementsByName в Powershell

У меня есть этот HTML-файл:

<html> 
    <head> 
     <title>Moo</title> 
    </head> 
    <body> 
     <h1>Hello world!</h1> 
     <ul id="a"> 
      <li>Bob 
      <li>Cat 
      <li>Fish 
     </ul> 
     <ul id="b"> 
      <li>Bob 
      <li>Dog 
      <li>Cow 
     </ul> 
     <div id="x"> 
      <b>What's the problem? Don't you <i>like soup</b> like this?</i>. 
     </div> 
    </body> 
</html> 

Да, это специально предназначен для сильно вложенными, как я играю с идеями (и тестирования для ограничения) на данный момент.

я загружаю этот файл в Powershell с MSHTML, выполнив (от https://stackoverflow.com/a/24989452/130352):

$html = new-object -ComObject "HTMLFile" 
$source = get-content -path $htmlFileName -raw 
$html.IHtmlDocument2_write($source) 

Если я сейчас:

$d = $html.getElementById("x") 
$d.TagName 

Я получаю ожидаемый результат (DIV). Однако если я это сделаю:

$d = $html.getElementsByTagName("div") 
$d[0].TagName 

У меня нет выхода. $d.length возвращает 1. $d[0] | ft без проблем выплевывает все свойства и ценности. Но доступ к свойствам из $ d [0] напрямую не возвращает ничего (т. Е. Запрашивает innerText, внешнийHtml и т. Д. Не возвращает никаких данных, в то время как поиск элемента по ID (то есть с getElementById) не имеет проблем, и я могу получить доступ к свойствам .

Точно так же, если я назначу переменной (т.е. $z = $d[0]), а затем работать непосредственно на $ г, я получаю один и тот же вопрос.

Что я упускаю?

ответ

2

Хороший вопрос.

Не удалось объяснить точно что происходит, b ut похоже, что

$d = $html.getElementsByTagName("div") 

возвращает коллекцию, которую PowerShell не знает, как изначально манипулировать.

Если вы пытаетесь выбрать некоторые (или все) из свойств, то переменная будет получить полностью заселена:

($d | select *)[0].tagname 

При использовании метода getElementsByTagName, вы могли бы сделать

$d = $html.getElementsByTagName("div") | select * 
$d[0].tagname 

It кажется, что трубопровод ComObject на Select-Object заставляет его отливать как PowerShell PSCustomObject, с которым вы тогда можете работать:

[PS]> ($html.getelementsbytagname("div") | select *).gettype() 

IsPublic IsSerial Name          BaseType 
-------- -------- ----          -------- 
True  False PSCustomObject       System.Object 


[PS]> ($html.getelementsbytagname("div")).gettype() 

IsPublic IsSerial Name          BaseType 
-------- -------- ----          -------- 
True  False __ComObject        System.MarshalByRefObject 

Не 100% уверен, что это «отвечает» вопрос, так как я не могу полностью объяснить поведение, но это жизнеспособная обходной путь по крайней мере

+0

Ах - это интересно. Я только что попробовал '$ d | % {$ _. tagname} 'для коллекции' ... bytagname', и это итерационно продолжается, и я получаю тэг. Так что да, это связано с коллекцией. 'GetElementsByTagName' возвращает' IXMLDOMNodeList'. Я предполагаю, что это фактически не может быть проиндексировано в (* отходит к MSDN *). –

+0

Да, все. IXMLDOMNodeList имеет метод 'item' для доступа к его частям, поэтому' $ d.Item (0) 'получает отдельный элемент.Или превратитесь в массив с '$ arr = $ d | % {$ _} '(который, я думаю, является другим способом сделать вашу трубу в' select * ') и использовать' $ arr [0] '. Или, другими словами, у меня должен быть RTFM. –

+0

Ха-ха, хорошо знать все равно! Имеет смысл думать об этом, список узлов не является массивом, поэтому нужно вызвать метод для итерации в определенную позицию, а не для прямой адресации. – arco444

Смежные вопросы