كيفية استرداد مساحات في ملفات XML باستخدام Xpath

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

  •  02-07-2019
  •  | 
  •  

سؤال

لدي ملف XML الذي يبدأ مثل هذا:

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

سوف تضطر إلى فتح الكثير من هذه الملفات.كل هذه قد يختلف الاسم ولكن لن يكون لها سوى مساحة واحدة في كل مرة (لن تجد اثنين من مساحات محددة في ملف xml واحد).

باستخدام XPath أود أن يكون تلقائي طريقة لإضافة إعطاء مساحة على مساحة المدير.حتى الآن أنا فقط يمكن أن تحصل على مساحة عن طريق تحليل ملف xml ولكن لدي XPathNavigator سبيل المثال ، يجب أن يكون لديك لطيفة ونظيفة طريقة للحصول على مساحات, صحيح ؟

- أو -

نظرا إلى أن ليس لدي سوى مساحة واحدة ، بطريقة ما تجعل XPath استخدام واحد فقط موجود في xml ، وبالتالي تجنب التبعثر رمز دائما إلحاق مساحة الاسم.

هل كانت مفيدة؟

المحلول

هناك عدد من التقنيات التي قد محاولة ؛ التي تستخدمها تعتمد على بالضبط ما هي المعلومات التي كنت بحاجة للحصول على الخروج من الوثيقة ، كيف صارمة كنت تريد أن تكون و كيف conformant 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