Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Cannot read XSD attribute with QXMLStreamReader



  • I need to parse the following XSD:

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
      <xs:element name = "elementName">
        <xs:simpleType>
          <xs:restriction base = "xs:string">
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
    </xs:schema>
    

    During the parsing I arrive to the restriction element. This is the code (rearranged) for parsing this element, that uses QXMLStreamReader

    void String::getFromBase() const {
      QXMLStreamReader m_node; // in true code it's a class member already initialized
      m_node.readNextStartElement();
      auto name = stripNamespace(m_node.name().toString()); // convert xs:restriction to restriction
      if (name != restriction) {
        throw Exception("Restriction is not found when reading string data");
      }
      bool hasBase{false};
      auto x = m_node.attributes().size(); // x is zero but it should be one
      for (const auto& it : m_node.attributes()) {
        auto attrName = stripNamespace(it.name().toString());
        if (attrName == "base") {
          hasBase = true;
          break;
        }
      }
      if (!hasBase) {
        throw Exception("Restriction needs 'base' attribute");
      }
      auto attribute = stripNamespace(m_node.attributes().value(BaseLabel).toString());
      if (attribute == "string") {
        int i = 0;
      }
    }
    

    When I run the code, the variable name is "restriction", so I arrive to the right position in the XML. But then when I retrieve attributes with attributes() the list is empty (in the code x is equal to zero) do I don't enter in the loop for cycling all attributes.

    What I'm doing wrong and what should I do for retrieving attributes of the node?



  • @jepessen said in Cannot read XSD attribute with QXMLStreamReader:

    (rearranged)

    I think this is the key. To be able to read the attributes m_node.isStartElement() must return true just before calling m_node.attributes(). What I suspect is happening is that in the real code you are moving the cursor beyond the StartElement before calling m_node.attributes()



  • @VRonin this is almost the real code I don't call readNextStartElement or readNextElement anywhere else in the function, so I' trying to retrieve attributes when m_node.name() is "restriction".

    This is the actual real code (A bit incomplete because I'm focusin on this issue):

    Tree::String::Ptr String::getFromBase() const {
      auto parsedNode = make_shared<Tree::String>();
      m_node.readNextStartElement();
      auto name = stripNamespace(m_node.name().toString());
      if (name != RestrictionLabel) {
        throw Exception("Restriction is not found when reading string data");
      }
      auto x = m_node.attributes().size();
      bool hasBase{ false };
      for (const auto& it : m_node.attributes()) {
        auto attrName = stripNamespace(it.name().toString());
        if (attrName == BaseLabel) {
          hasBase = true;
          break;
        }
      }
      if (!hasBase) {
        throw Exception("Restriction needs 'base' attribute");
      }
      auto attribute = stripNamespace(m_node.attributes().value(BaseLabel).toString());
      if (attribute == StringLabel) {
        int i = 0;
      }
      return parsedNode;
    }
    


  • I'm sorry but you must be moving the cursor in some way. Try putting Q_ASSERT(m_node.isStartElement()); just before auto x = m_node.attributes().size();

    This example parses the XSD you provided correctly (I also let QXmlStreamReader handle namespaces instead of having to write custom code for it):

    int main()
    {
        const QString xmlText(R"***(<?xml version="1.0" encoding="UTF-8"?>
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
          <xs:element name = "elementName">
            <xs:simpleType>
              <xs:restriction base = "xs:string">
              </xs:restriction>
            </xs:simpleType>
          </xs:element>
        </xs:schema>)***"
        );
        QXmlStreamReader reader(xmlText);
        while (!reader.atEnd()) {
            switch(reader.readNext()){
            case QXmlStreamReader::StartDocument:
                qDebug("Start of document");
                break;
            case QXmlStreamReader::EndDocument:
                qDebug("End of document");
                break;
            case QXmlStreamReader::StartElement:{
                qDebug() << "Started Element: " << reader.name();
                const auto attr = reader.attributes();
                qDebug() << "Number of Attributes: " << attr.size() << " Attributes:";
                for(auto&& att : attr)
                    qDebug() << att.name() << " = " << att.value();
            }
                break;
            case QXmlStreamReader::EndElement:
                qDebug() << "Finished Element: " << reader.name();
                break;
            default:
                break;
            }
        }
        return 0;
    }