XPath를 사용하여 XML 파일에서 네임 스페이스를 검색하는 방법

StackOverflow https://stackoverflow.com/questions/122463

  •  02-07-2019
  •  | 
  •  

문제

다음과 같이 시작하는 XML 파일이 있습니다.

<Elements name="Entities" xmlns="XS-GenerationToolElements">

이 파일을 많이 열어야합니다. 이들 각각에는 다른 네임 스페이스가 있지만 한 번에 하나의 네임 스페이스 만 있습니다 (하나의 XML 파일에 정의 된 두 개의 네임 스페이스를 찾지 못합니다).

XPath를 사용하여 주어진 네임 스페이스를 네임 스페이스 관리자에 추가하는 자동 방법을 원합니다. 지금까지 XML 파일을 구문 분석하여 네임 스페이스 만 얻을 수 있었지만 XPathNavigator 인스턴스가 있으며 네임 스페이스를 얻을 수있는 멋진 방법이 있어야합니까?

-- 또는 --

하나의 네임 스페이스 만 있으면 XPath가 XML에 존재하는 유일한 네임 스페이스를 사용하여 항상 네임 스페이스를 추가하여 코드를 혼란스럽게하지 않도록합니다.

도움이 되었습니까?

해결책

시도 할 수있는 몇 가지 기술이 있습니다. 당신이 사용하는 것은 문서에서 얻는 데 필요한 정보, 당신이 얼마나 엄격한 지, 그리고 당신이 사용하는 XPath 구현이 얼마나 부합하는지 정확히 달라집니다.

특정 접두사와 관련된 네임 스페이스 URI를 얻는 한 가지 방법은 namespace:: 중심선. 이렇게하면 이름이 접두사이고 네임 스페이스 URI 인 네임 스페이스 노드가 제공됩니다. 예를 들어, 경로를 사용하여 문서 요소에서 기본 네임 스페이스 URI를 가져올 수 있습니다.

/*/namespace::*[name()='']

이를 사용하여 XPathNavigator의 네임 스페이스 연결을 설정할 수 있습니다. 그러나 경고를받습니다 namespace:: 축은 항상 구현되지는 않는 XPath 1.0의 코너 중 하나입니다.

그 네임 스페이스 URI를 얻는 두 번째 방법은 namespace-uri() 문서 요소의 기능 (당신이 말한 것은 항상 그 네임 스페이스에 있습니다). 표현식:

namespace-uri(/*)

그 네임 스페이스를 줄 것입니다.

대안은 해당 네임 스페이스와 접두사를 연관시키는 것을 잊어 버리고 경로를 네임 스페이스없이 만드는 것입니다. 당신은 그것을 사용하여 이것을 할 수 있습니다 local-name() 네임 스페이스를 모르는 요소를 참조해야 할 때마다 기능하십시오. 예를 들어:

//*[local-name() = 'Element']

한 걸음 더 나아가서 실제로 원하는 경우 문서 요소 중 하나에 대해 요소의 네임 스페이스 URI를 테스트 할 수 있습니다.

//*[local-name() = 'Element' and namespace-uri() = namespace-uri(/*)]

네임 스페이스가 당신에게 아무 의미가없는 것처럼 보이는 최종 옵션은 네임 스페이스를 제거하는 필터를 통해 XML을 실행하는 것입니다. 그러면 XPath에서 그들에 대해 전혀 걱정할 필요가 없습니다. 가장 쉬운 방법은 단순히 제거하는 것입니다. xmlns 정규 표현으로 속성이지만 동시에 다른 정리를해야한다면 더 복잡한 일을 할 수 있습니다.

다른 팁

이 40 줄 XSLT 변환은 주어진 XML 문서의 네임 스페이스에 대한 모든 유용한 정보를 제공합니다.:

<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:ext="http://exslt.org/common"
   exclude-result-prefixes="ext"
>

<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:strip-space elements="*"/>

<xsl:key name="kNsByNsUri" match="ns" use="@uri"/>

<xsl:variable name="vXmlNS" 
    select="'http://www.w3.org/XML/1998/namespace'"/>

<xsl:template match="/">
  <xsl:variable name="vrtfNamespaces">
    <xsl:for-each select=
      "//namespace::*
             [not(. = $vXmlNS)
             and
              . = namespace-uri(..)
           ]">
      <ns element="{name(..)}"
          prefix="{name()}" uri="{.}"/>
    </xsl:for-each>
  </xsl:variable>

  <xsl:variable name="vNamespaces"
    select="ext:node-set($vrtfNamespaces)/*"/>

  <namespaces>
          <xsl:for-each select=
           "$vNamespaces[generate-id()
                        =
                         generate-id(key('kNsByNsUri',@uri)[1])
                        ]">
            <namespace uri="{@uri}">
              <xsl:for-each select="key('kNsByNsUri',@uri)/@element">
                <element name="{.}" prefix="{../@prefix}"/>
              </xsl:for-each>
            </namespace>
          </xsl:for-each>
  </namespaces>
</xsl:template>

다음 XML 문서에 적용될 때 :

<a xmlns="my:def1" xmlns:n1="my:n1"
   xmlns:n2="my:n2" xmlns:n3="my:n3">
  <b>
    <n1:d/>
  </b>
  <n1:c>
    <n2:e>
      <f/>
    </n2:e>
  </n1:c>
  <n2:g/>
</a>

원하는 결과가 생성됩니다.

<namespaces>
   <namespace uri="my:def1">
      <element name="a" prefix=""/>
      <element name="b" prefix=""/>
      <element name="f" prefix=""/>
   </namespace>
   <namespace uri="my:n1">
      <element name="n1:d" prefix="n1"/>
      <element name="n1:c" prefix="n1"/>
   </namespace>
   <namespace uri="my:n2">
      <element name="n2:e" prefix="n2"/>
      <element name="n2:g" prefix="n2"/>
   </namespace>
</namespaces>

불행히도 XPath에는 "기본 네임 스페이스"개념이 없습니다. XPath 컨텍스트가있는 접두사가있는 네임 스페이스를 등록한 다음 XPath 표현식에서 접두사를 사용해야합니다. 그것은 매우 장점의 XPath를 의미하지만 XPath 1의 기본 단점입니다. 분명히 XPath 2는 이것을 다룰 것이지만 지금은 당신에게 쓸모가 없습니다.

네임 스페이스에 대한 XML 문서를 프로그래밍 방식으로 검토하고 해당 네임 스페이스를 XPath 컨텍스트의 접두사와 연결 한 다음 XPath 표현식에서 접두사를 사용하는 것이 좋습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top