Чтение пространств имен из XML-документа - PullRequest
2 голосов
/ 16 августа 2010

как мне прочитать пространства имен из документа XML?

<fx:FIBEX xmlns:fx="http://www.asam.net/xml/fbx" xmlns:can="http://www.asam.net/xml/fbx/can" xmlns:flexray="http://www.asam.net/xml/fbx/flexray"      
    xmlns:ho="http://www.asam.net/xml" xmlns:ni="http://www.ni.com/xnet"    
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
    xsi:schemaLocation="http://www.asam.net/xml/fbx/all http://www.asam.net/xml/fbx/2_0_1/xsd/fibex4multiplatform.xsd"     
     VERSION="2.0.1">

Как я могу прочитать пространства имен из этого корневого элемента?

На самом деле главный вопрос - «как получить узел, используя xPath, как

//fx:ELEMENTS/fx:CLUSTERS/fx:CLUSTER 

?

Я попробовал XmlDocument.SelectSingleNode () с этой строкой, но это дало мне ошибку об XmlNamespaces, и я обнаружил в Google, что вам нужно иметь XmlNamespaceManager.

1 Ответ

3 голосов
/ 17 августа 2010

Ваш вопрос на самом деле включает в себя два разных вопроса:

  1. Как выбрать элементы, которые объявлены в некотором пространстве имен?
  2. Как выбрать узлы пространства имен элемента?

Вопрос 1

Чтобы выбрать узлы, которые находятся в некотором пространстве имен, вам нужно указать отображение префикса-пространства имен. Все процессоры XPath позволяют это, но как это сделать, зависит от реализации. Обычно это означает создание пары - префикса и URI - и затем добавление этой пары в качестве контекста пространства имен. URI важен. Он должен быть точно таким же, как URI пространства имен вашего элемента. Префикс не обязательно должен совпадать с тем, который использовался в документе, он может быть любым, но вам нужен префикс, даже если элемент находился в пространстве имен по умолчанию и поэтому не имеет префикса.

После того, как ваш распознаватель XPath узнает о необходимых пространствах имен, вы можете выбирать элементы так же, как и в своем вопросе: //fx:ELEMENTS/fx:CLUSTERS/fx:CLUSTER. Убедитесь, что вы используете тот же префикс, который вы использовали в сопоставлении (если префикс отличается от префикса в документе). Обратите внимание, что в выражениях XPath элементы без префикса всегда имеют без пространства имен , поэтому вам необходимо использовать префиксы пространства имен в выражении XPath даже при выборе элементов из пространства имен по умолчанию.

Для грязных хаков вы также можете попытаться полностью избежать использования имен элементов. В Xpath * соответствует всем элементам узлов и node() всем узлам. Вы можете сузить выбор с помощью творческого использования предикатов, которые используют такие функции, как name(), local-name(), position() или last(). Например, выражение XPath //*[name()='fx:CLUSTER'] выбирает все элементы с префиксом "fx" и локальным именем "CLUSTER" , и это работает даже без отображения префикса-пространства имен . Однако следует помнить, что в XML префиксы не гарантируются такими же, и они также могут быть повторно использованы / переопределены в документе, так что один и тот же префикс относится к разным URI в разных частях документа.

Вопрос 2

Узлы пространства имен выбираются по оси namespace::. Локальная часть имени узла пространства имен - это префикс пространства имен, а строковое значение - URI пространства имен. Узел для пространства имен по умолчанию имеет пустое имя. Вы можете выбрать все узлы пространства имен с помощью URI http://example.com/ns с выражением XPath //namespace::*[.=http://example.com/ns] и выбрать все узлы пространства имен с префиксом «px:», используя //namespace::*[name()='px']. Как и в случае с узлами атрибутов, узел пространства имен не является дочерним по отношению к элементу, которому он принадлежит, однако элемент является родителем этого узла пространства имен. Используйте ось parent::, чтобы получить владельца узла пространства имен.

Пространства имен не нужно объявлять в корневом элементе (хотя это распространено и весьма разумно), но они могут быть объявлены в любом элементе. Поиск узлов пространства имен корневого элемента не гарантирует, что вы знаете все URI и префиксы пространства имен, используемые в этом документе.

Подвох состоит в том, что все элементы имеют один или несколько узлов пространства имен независимо от того, имеет ли элемент явные объявления пространства имен или нет. Элементы имеют набор узлов пространства имен, один для пространства имен по умолчанию, если он находится в области действия для этого элемента, и один для каждого префикса, который находится в области действия для этого элемента, включая префикс xml. Ниже приведен пример кода узлов пространства имен в различных ситуациях.

В этом примере 3 файла: документ XML с различными пространствами имен, документ XSLT, который печатает значения узлов пространства имен для каждого элемента, и выходные данные документа XSLT.

Обработанный документ XML

<root xmlns:ns1="http://example.com/namespace-1">
 <nothing/>
 <default xmlns="http://example.com/default">
  <override xmlns=""/>
 </default>
 <ns1:namespace-1 ns1:attribute-1="x" attribute-2="y"/>
 <ns2:namespace-2 xmlns:ns2="http://example.com/namespace-2"/>
</root>

XSLT документ

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output encoding="utf-8" method="text"/>

 <xsl:template match="/">
  <xsl:text>Find and print all element names and namespace nodes&#10;&#10;</xsl:text>
  <xsl:apply-templates select="//*|//@*"/>
  <xsl:text>End of tests&#10;</xsl:text>
 </xsl:template>

 <xsl:template match="*|@*">
  <xsl:text>name          = "</xsl:text>
  <xsl:value-of select="name(.)"/>
  <xsl:text>"&#10;</xsl:text>
  <xsl:text>namespace URI = "</xsl:text>
  <xsl:value-of select="namespace-uri(.)"/>
  <xsl:text>"&#10;</xsl:text>
  <xsl:text>This node has </xsl:text>
  <xsl:value-of select="count(./namespace::*)"/>
  <xsl:text> namespace nodes:&#10;</xsl:text>
  <xsl:for-each select="./namespace::*">
   <xsl:value-of select="position()"/>
   <xsl:text>. namespace prefix = "</xsl:text>
   <xsl:value-of select="name(.)"/>
   <xsl:text>"&#10;   namespace URI    = "</xsl:text>
   <xsl:value-of select="."/>
   <xsl:text>"&#10;</xsl:text>
  </xsl:for-each>
  <xsl:text>&#10;</xsl:text>
 </xsl:template>
</xsl:stylesheet>

Вывод документа XSLT

Find and print all element names and namespace nodes

name          = "root"
namespace URI = ""
This node has 2 namespace nodes:
1. namespace prefix = "xml"
   namespace URI    = "http://www.w3.org/XML/1998/namespace"
2. namespace prefix = "ns1"
   namespace URI    = "http://example.com/namespace-1"

name          = "nothing"
namespace URI = ""
This node has 2 namespace nodes:
1. namespace prefix = "xml"
   namespace URI    = "http://www.w3.org/XML/1998/namespace"
2. namespace prefix = "ns1"
   namespace URI    = "http://example.com/namespace-1"

name          = "default"
namespace URI = "http://example.com/default"
This node has 3 namespace nodes:
1. namespace prefix = "xml"
   namespace URI    = "http://www.w3.org/XML/1998/namespace"
2. namespace prefix = "ns1"
   namespace URI    = "http://example.com/namespace-1"
3. namespace prefix = ""
   namespace URI    = "http://example.com/default"

name          = "override"
namespace URI = ""
This node has 3 namespace nodes:
1. namespace prefix = "xml"
   namespace URI    = "http://www.w3.org/XML/1998/namespace"
2. namespace prefix = "ns1"
   namespace URI    = "http://example.com/namespace-1"
3. namespace prefix = ""
   namespace URI    = ""

name          = "ns1:namespace-1"
namespace URI = "http://example.com/namespace-1"
This node has 2 namespace nodes:
1. namespace prefix = "xml"
   namespace URI    = "http://www.w3.org/XML/1998/namespace"
2. namespace prefix = "ns1"
   namespace URI    = "http://example.com/namespace-1"

name          = "ns1:attribute-1"
namespace URI = "http://example.com/namespace-1"
This node has 0 namespace nodes:

name          = "attribute-2"
namespace URI = ""
This node has 0 namespace nodes:

name          = "ns2:namespace-2"
namespace URI = "http://example.com/namespace-2"
This node has 3 namespace nodes:
1. namespace prefix = "xml"
   namespace URI    = "http://www.w3.org/XML/1998/namespace"
2. namespace prefix = "ns1"
   namespace URI    = "http://example.com/namespace-1"
3. namespace prefix = "ns2"
   namespace URI    = "http://example.com/namespace-2"

End of tests

Некоторые вещи, которые показывает пример:

  1. У всех элементов есть узел для пространства имен xml
  2. Элементы root и nothing имеют узел для префикса пространства имен "namespace-1", хотя элементы не используют его
  3. Имя пространства имен по умолчанию пустое, как видно на default
  4. Элемент root не имеет узла для пространства имен по умолчанию, но override имеет, хотя ни один из них не принадлежит пространству имен. Это связано с тем, что override имеет объявление пространства имен по умолчанию, только в этом случае оно сбрасывается на пустое.
  5. namespace-1 имеет узлы пространства имен, аналогичные элементу nothing, хотя другой префикс и использует пространство имен, а другой нет
  6. namespace-2 - единственный элемент, который имеет узел для префикса ns2, поскольку родственные элементы не входят в область действия для объявления пространства имен
  7. Как ни странно, атрибуты могут принадлежать пространству имен, но у них все еще нет узлов пространства имен. Согласно спецификациям, узлы пространства имен также имеют расширенное имя, но URI всегда равен нулю.

При сравнении пространств имен имейте в виду, что элементы не разделяют узлы пространства имен. Даже если родитель и потомок будут иметь все одинаковые узлы пространства имен, они на самом деле не являются одинаковыми узлами. Точно так же, как переменные двух разных объектов не одинаковы, даже если они будут иметь одно и то же имя и одно и то же значение.

...